dexterm-cli 0.1.6 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/packages/agents/src/schema.js +22 -1
- package/dist/packages/agents/src/story.js +11 -2
- package/dist/packages/agents/src/tiers.js +27 -2
- package/dist/packages/agents/src/tools.js +30 -2
- package/dist/packages/autotrade/assets/exit-profile.schema.json +492 -0
- package/dist/packages/autotrade/assets/profiles/moonbag.json +46 -0
- package/dist/packages/autotrade/assets/profiles/runner.json +88 -0
- package/dist/packages/autotrade/assets/profiles/scalp.json +88 -0
- package/dist/packages/autotrade/assets/profiles/swing.json +88 -0
- package/dist/packages/autotrade/assets/strategies/moonbag.json +101 -0
- package/dist/packages/autotrade/assets/strategies/runner.json +101 -0
- package/dist/packages/autotrade/assets/strategies/sample-dip-ladder.json +188 -0
- package/dist/packages/autotrade/assets/strategies/scalp.json +98 -0
- package/dist/packages/autotrade/assets/strategies/swing.json +97 -0
- package/dist/packages/autotrade/assets/strategies/yolo.json +157 -0
- package/dist/packages/autotrade/assets/tapes/yolo-rehearsal.json +1 -0
- package/dist/packages/autotrade/src/account.js +74 -0
- package/dist/packages/autotrade/src/backtest.js +357 -0
- package/dist/packages/autotrade/src/basis-text.js +32 -0
- package/dist/packages/autotrade/src/chat/approvals.js +484 -0
- package/dist/packages/autotrade/src/chat/audit.js +140 -0
- package/dist/packages/autotrade/src/chat/config.js +93 -0
- package/dist/packages/autotrade/src/chat/connector.js +24 -0
- package/dist/packages/autotrade/src/chat/control.js +103 -0
- package/dist/packages/autotrade/src/chat/fake.js +100 -0
- package/dist/packages/autotrade/src/chat/format.js +71 -0
- package/dist/packages/autotrade/src/chat/hub.js +187 -0
- package/dist/packages/autotrade/src/chat/index.js +18 -0
- package/dist/packages/autotrade/src/chat/notify.js +292 -0
- package/dist/packages/autotrade/src/chat/pairing.js +46 -0
- package/dist/packages/autotrade/src/chat/redact.js +48 -0
- package/dist/packages/autotrade/src/chat/secrets.js +99 -0
- package/dist/packages/autotrade/src/chat/service.js +248 -0
- package/dist/packages/autotrade/src/chat/telegram.js +290 -0
- package/dist/packages/autotrade/src/desk-executor.js +188 -0
- package/dist/packages/autotrade/src/engine.js +387 -0
- package/dist/packages/autotrade/src/execution-port.js +97 -0
- package/dist/packages/autotrade/src/fleet-config.js +169 -0
- package/dist/packages/autotrade/src/fleet-control.js +276 -0
- package/dist/packages/autotrade/src/fleet.js +639 -0
- package/dist/packages/autotrade/src/index.js +53 -0
- package/dist/packages/autotrade/src/ledger.js +108 -0
- package/dist/packages/autotrade/src/live-source.js +182 -0
- package/dist/packages/autotrade/src/monitor-daemon.js +715 -0
- package/dist/packages/autotrade/src/monitor.js +190 -0
- package/dist/packages/autotrade/src/ollama-sessions.js +137 -0
- package/dist/packages/autotrade/src/paper-accounts.js +72 -0
- package/dist/packages/autotrade/src/replay.js +198 -0
- package/dist/packages/autotrade/src/runner-config.js +99 -0
- package/dist/packages/autotrade/src/runner.js +872 -0
- package/dist/packages/autotrade/src/safety.js +243 -0
- package/dist/packages/autotrade/src/session.js +269 -0
- package/dist/packages/autotrade/src/sessions.js +503 -0
- package/dist/packages/autotrade/src/store.js +250 -0
- package/dist/packages/autotrade/src/strategy.js +256 -0
- package/dist/packages/autotrade/src/trade-ledger.js +241 -0
- package/dist/packages/autotrade/src/yolo.js +140 -0
- package/dist/packages/cli/assets/claude/analyst-system.md +4 -4
- package/dist/packages/cli/assets/claude/plugin/skills/token-dossier/SKILL.md +1 -1
- package/dist/packages/cli/src/ai-cmd.js +412 -0
- package/dist/packages/cli/src/analyst/backend.js +82 -15
- package/dist/packages/cli/src/analyst/codex.js +14 -9
- package/dist/packages/cli/src/analyst/ollama.js +263 -0
- package/dist/packages/cli/src/analyst/session.js +5 -2
- package/dist/packages/cli/src/app-help-gen.js +44 -8
- package/dist/packages/cli/src/autotrade-cmd/audit.js +57 -0
- package/dist/packages/cli/src/autotrade-cmd/backtest.js +199 -0
- package/dist/packages/cli/src/autotrade-cmd/flatten.js +64 -0
- package/dist/packages/cli/src/autotrade-cmd/fleet.js +397 -0
- package/dist/packages/cli/src/autotrade-cmd/requests.js +79 -0
- package/dist/packages/cli/src/autotrade-cmd/run.js +413 -0
- package/dist/packages/cli/src/autotrade-cmd/stop.js +76 -0
- package/dist/packages/cli/src/autotrade-cmd/strategies.js +198 -0
- package/dist/packages/cli/src/autotrade-cmd/strategy-control.js +174 -0
- package/dist/packages/cli/src/autotrade-cmd/telegram-host.js +101 -0
- package/dist/packages/cli/src/autotrade-cmd.js +168 -0
- package/dist/packages/cli/src/display.js +156 -17
- package/dist/packages/cli/src/doctor.js +62 -3
- package/dist/packages/cli/src/export.js +10 -2
- package/dist/packages/cli/src/index.js +1 -1
- package/dist/packages/cli/src/ledger-cmd.js +288 -0
- package/dist/packages/cli/src/live/chart-fills.js +46 -0
- package/dist/packages/cli/src/live/index.js +23 -89
- package/dist/packages/cli/src/live/screens/token-live.js +9 -6
- package/dist/packages/cli/src/live/trade.js +12 -457
- package/dist/packages/cli/src/live/watchlist.js +1 -1
- package/dist/packages/cli/src/main.js +147 -190
- package/dist/packages/cli/src/mcp-cmd.js +7 -1
- package/dist/packages/cli/src/plan-cmd.js +1 -1
- package/dist/packages/cli/src/pnl-app.js +31 -21
- package/dist/packages/cli/src/pnl-card.js +158 -21
- package/dist/packages/cli/src/popup.js +22 -6
- package/dist/packages/cli/src/record-cmd.js +141 -20
- package/dist/packages/cli/src/screens/agent-hud.js +34 -2
- package/dist/packages/cli/src/screens/analyst-session.js +7 -4
- package/dist/packages/cli/src/screens/analyst.js +3 -2
- package/dist/packages/cli/src/screens/autotrade-keys.js +169 -0
- package/dist/packages/cli/src/screens/autotrade-proposals.js +123 -0
- package/dist/packages/cli/src/screens/autotrade-screen.js +725 -0
- package/dist/packages/cli/src/screens/autotrade-ui.js +640 -0
- package/dist/packages/cli/src/screens/autotrade-worker.js +89 -0
- package/dist/packages/cli/src/screens/brain.js +37 -11
- package/dist/packages/cli/src/screens/overlay.js +5 -2
- package/dist/packages/cli/src/screens/plans.js +5 -17
- package/dist/packages/cli/src/screens/pnl-chip.js +9 -8
- package/dist/packages/cli/src/screens/positions.js +6 -28
- package/dist/packages/cli/src/screens/ticket.js +38 -205
- package/dist/packages/cli/src/screens/token.js +3 -3
- package/dist/packages/cli/src/state.js +25 -19
- package/dist/packages/cli/src/telegram-cmd.js +451 -0
- package/dist/packages/cli/src/trade.js +3 -128
- package/dist/packages/cli/src/version.js +1 -1
- package/dist/packages/cli/src/wallet-cmd.js +39 -340
- package/dist/packages/cli/src/wallet-command.js +8 -11
- package/dist/packages/cli/src/widgets.js +0 -12
- package/dist/packages/custom/src/config.js +20 -2
- package/dist/packages/custom/src/schema.js +35 -10
- package/dist/packages/custom/src/workspace.js +3 -3
- package/dist/packages/data/src/basis.js +191 -0
- package/dist/packages/data/src/detail.js +53 -2
- package/dist/packages/data/src/index.js +0 -14
- package/dist/packages/data/src/store.js +14 -5
- package/dist/packages/data/src/trade/agent/paper-desk.js +228 -16
- package/dist/packages/data/src/trade/agent/rendezvous.js +3 -2
- package/dist/packages/data/src/trade/bridge.js +4 -102
- package/dist/packages/data/src/trade/ledger/export.js +101 -0
- package/dist/packages/data/src/trade/ledger/file.js +135 -0
- package/dist/packages/data/src/trade/ledger/fold.js +191 -0
- package/dist/packages/data/src/trade/ledger/index.js +9 -0
- package/dist/packages/data/src/trade/ledger/schema.js +83 -0
- package/dist/packages/data/src/trade/ledger/sources.js +307 -0
- package/dist/packages/data/src/trade/ledger/stats.js +123 -0
- package/dist/packages/data/src/trade/ledger/tags.js +116 -0
- package/dist/packages/data/src/trade/ledger/view.js +51 -0
- package/dist/packages/data/src/trade/plans/index.js +0 -1
- package/dist/packages/data/src/trade/plans/service.js +3 -27
- package/dist/packages/mcp/assets/kb/app-help/autotrade-chat.md +48 -0
- package/dist/packages/mcp/assets/kb/app-help/autotrade-parallel.md +42 -0
- package/dist/packages/mcp/assets/kb/app-help/autotrade-runner.md +35 -0
- package/dist/packages/mcp/assets/kb/app-help/autotrade-stop.md +37 -0
- package/dist/packages/mcp/assets/kb/app-help/autotrade-strategies.md +35 -0
- package/dist/packages/mcp/assets/kb/app-help/autotrade-telegram.md +40 -0
- package/dist/packages/mcp/assets/kb/app-help/chart-trade-markers.md +42 -0
- package/dist/packages/mcp/assets/kb/app-help/link-a-wallet.md +4 -10
- package/dist/packages/mcp/assets/kb/app-help/live-trading.md +38 -0
- package/dist/packages/mcp/assets/kb/app-help/live-yolo.md +34 -0
- package/dist/packages/mcp/assets/kb/app-help/order-plans.md +1 -1
- package/dist/packages/mcp/assets/kb/app-help/price-or-marketcap.md +5 -2
- package/dist/packages/mcp/assets/kb/app-help/screen-analyst.md +3 -0
- package/dist/packages/mcp/assets/kb/app-help/screen-autotrade.md +217 -0
- package/dist/packages/mcp/assets/kb/app-help/screen-kol.md +3 -0
- package/dist/packages/mcp/assets/kb/app-help/screen-newpairs.md +3 -0
- package/dist/packages/mcp/assets/kb/app-help/screen-positions.md +3 -0
- package/dist/packages/mcp/assets/kb/app-help/screen-screener.md +3 -0
- package/dist/packages/mcp/assets/kb/app-help/screen-token.md +3 -0
- package/dist/packages/mcp/assets/kb/app-help/screen-trending.md +3 -0
- package/dist/packages/mcp/assets/kb/app-help/screen-watchlist.md +3 -0
- package/dist/packages/mcp/assets/kb/app-help/standing-mandates.md +1 -1
- package/dist/packages/mcp/assets/kb/app-help/trade-ledger.md +54 -0
- package/dist/packages/mcp/assets/kb/app-help/use-local-model.md +38 -0
- package/dist/packages/mcp/assets/kb/docs/docs-agents-agent-paper-trading.md +4 -1
- package/dist/packages/mcp/assets/kb/docs/docs-agents-reading-your-trade-ledger.md +31 -0
- package/dist/packages/mcp/assets/kb/docs/docs-agents-untrusted-by-default.md +1 -1
- package/dist/packages/mcp/assets/kb/docs/docs-analyst-if-claude-is-missing.md +1 -1
- package/dist/packages/mcp/assets/kb/docs/docs-analyst-use-a-local-model-instead.md +27 -0
- package/dist/packages/mcp/assets/kb/docs/docs-analyst-what-it-sees.md +2 -0
- package/dist/packages/mcp/assets/kb/docs/docs-autotrade-backtests-and-their-limits.md +56 -0
- package/dist/packages/mcp/assets/kb/docs/docs-autotrade-change-a-strategy-by-chat.md +49 -0
- package/dist/packages/mcp/assets/kb/docs/docs-autotrade-checking-the-record-of-a-run.md +28 -0
- package/dist/packages/mcp/assets/kb/docs/docs-autotrade-comparing-them.md +41 -0
- package/dist/packages/mcp/assets/kb/docs/docs-autotrade-exits-and-wakes.md +76 -0
- package/dist/packages/mcp/assets/kb/docs/docs-autotrade-how-a-stop-reaches-the-runner.md +32 -0
- package/dist/packages/mcp/assets/kb/docs/docs-autotrade-on-the-q-screen.md +37 -0
- package/dist/packages/mcp/assets/kb/docs/docs-autotrade-one-strategy-or-all-of-them.md +35 -0
- package/dist/packages/mcp/assets/kb/docs/docs-autotrade-paper-accounts.md +50 -0
- package/dist/packages/mcp/assets/kb/docs/docs-autotrade-presets.md +37 -0
- package/dist/packages/mcp/assets/kb/docs/docs-autotrade-running-it-all-day.md +31 -0
- package/dist/packages/mcp/assets/kb/docs/docs-autotrade-sessions-and-their-limits.md +31 -0
- package/dist/packages/mcp/assets/kb/docs/docs-autotrade-several-strategies-at-once.md +33 -0
- package/dist/packages/mcp/assets/kb/docs/docs-autotrade-stopping-it.md +35 -0
- package/dist/packages/mcp/assets/kb/docs/docs-autotrade-strategies-and-presets.md +34 -0
- package/dist/packages/mcp/assets/kb/docs/docs-autotrade-the-autotrade-json-file.md +48 -0
- package/dist/packages/mcp/assets/kb/docs/docs-autotrade-the-heartbeat.md +27 -0
- package/dist/packages/mcp/assets/kb/docs/docs-autotrade-the-run-file-and-the-heartbeat.md +34 -0
- package/dist/packages/mcp/assets/kb/docs/docs-autotrade-the-runner-and-candidate-sessions.md +45 -0
- package/dist/packages/mcp/assets/kb/docs/docs-autotrade-what-each-session-shows-first.md +31 -0
- package/dist/packages/mcp/assets/kb/docs/docs-autotrade-what-it-costs-claude-usage-per-session.md +58 -0
- package/dist/packages/mcp/assets/kb/docs/docs-autotrade-what-it-is-paper-self-directed.md +43 -0
- package/dist/packages/mcp/assets/kb/docs/docs-autotrade-what-it-will-not-do.md +31 -0
- package/dist/packages/mcp/assets/kb/docs/docs-autotrade-which-account-day-caps-and-the-usage-guard.md +44 -0
- package/dist/packages/mcp/assets/kb/docs/docs-autotrade-your-strategies.md +37 -0
- package/dist/packages/mcp/assets/kb/docs/docs-autotrade.md +22 -0
- package/dist/packages/mcp/assets/kb/docs/docs-beginners-before-any-experimental-trading.md +2 -2
- package/dist/packages/mcp/assets/kb/docs/docs-beginners.md +1 -1
- package/dist/packages/mcp/assets/kb/docs/docs-configuration-chart-markers.md +30 -0
- package/dist/packages/mcp/assets/kb/docs/docs-configuration-chart-y-axis.md +1 -1
- package/dist/packages/mcp/assets/kb/docs/docs-configuration-environment-variables.md +4 -1
- package/dist/packages/mcp/assets/kb/docs/docs-configuration-files-on-disk.md +1 -0
- package/dist/packages/mcp/assets/kb/docs/docs-configuration-headless-recorder-dexterm-record.md +3 -1
- package/dist/packages/mcp/assets/kb/docs/docs-configuration-price-display-mode.md +8 -6
- package/dist/packages/mcp/assets/kb/docs/docs-copy-trading-stage-2-the-one-key-mirror-ticket-a-proposal.md +1 -1
- package/dist/packages/mcp/assets/kb/docs/docs-copy-trading-stage-3-capped-auto-mirror-default-off-less.md +1 -1
- package/dist/packages/mcp/assets/kb/docs/docs-copy-trading-what-is-proven-what-is-not.md +1 -1
- package/dist/packages/mcp/assets/kb/docs/docs-copy-trading.md +1 -1
- package/dist/packages/mcp/assets/kb/docs/docs-data-sources-recorded-history-and-retention.md +36 -0
- package/dist/packages/mcp/assets/kb/docs/docs-data-sources-sources.md +1 -0
- package/dist/packages/mcp/assets/kb/docs/docs-getting-started-first-run.md +1 -1
- package/dist/packages/mcp/assets/kb/docs/docs-getting-started-install.md +3 -3
- package/dist/packages/mcp/assets/kb/docs/docs-getting-started-requirements.md +1 -1
- package/dist/packages/mcp/assets/kb/docs/docs-getting-started.md +1 -1
- package/dist/packages/mcp/assets/kb/docs/docs-live-trading-changed-in-0-1-7.md +26 -0
- package/dist/packages/mcp/assets/kb/docs/docs-live-trading-stopping.md +28 -0
- package/dist/packages/mcp/assets/kb/docs/docs-live-trading-the-short-version.md +34 -0
- package/dist/packages/mcp/assets/kb/docs/docs-live-trading-using-a-trading-bot-with-dexterm.md +33 -0
- package/dist/packages/mcp/assets/kb/docs/docs-live-trading-what-dexterm-does-not-do.md +30 -0
- package/dist/packages/mcp/assets/kb/docs/docs-live-trading-what-dexterm-does.md +29 -0
- package/dist/packages/mcp/assets/kb/docs/docs-live-trading.md +23 -0
- package/dist/packages/mcp/assets/kb/docs/docs-ollama-another-machine.md +28 -0
- package/dist/packages/mcp/assets/kb/docs/docs-ollama-autotrade-on-a-local-model.md +29 -0
- package/dist/packages/mcp/assets/kb/docs/docs-ollama-check-your-model-dexterm-ai-probe.md +38 -0
- package/dist/packages/mcp/assets/kb/docs/docs-ollama-how-we-checked.md +27 -0
- package/dist/packages/mcp/assets/kb/docs/docs-ollama-models-without-tool-calling.md +32 -0
- package/dist/packages/mcp/assets/kb/docs/docs-ollama-pick-the-engine-globally-or-per-surface.md +43 -0
- package/dist/packages/mcp/assets/kb/docs/docs-ollama-restriction-profiles.md +35 -0
- package/dist/packages/mcp/assets/kb/docs/docs-ollama-set-it-up-in-two-minutes.md +39 -0
- package/dist/packages/mcp/assets/kb/docs/docs-ollama-troubleshooting.md +35 -0
- package/dist/packages/mcp/assets/kb/docs/docs-ollama-what-runs-on-a-local-model.md +39 -0
- package/dist/packages/mcp/assets/kb/docs/docs-ollama-what-stays-outside-the-model.md +36 -0
- package/dist/packages/mcp/assets/kb/docs/docs-ollama-which-model.md +38 -0
- package/dist/packages/mcp/assets/kb/docs/docs-ollama-your-own-agent-on-the-local-model.md +28 -0
- package/dist/packages/mcp/assets/kb/docs/docs-ollama.md +28 -0
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-letting-an-agent-paper-trade-experimental.md +3 -4
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-link-a-wallet-read-only.md +30 -0
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-order-plans-and-standing-mandates.md +3 -4
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-panic.md +4 -7
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-paper-only-mandates.md +6 -7
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-pnl-cards.md +7 -7
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-the-safety-model.md +34 -0
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-the-ticket.md +3 -4
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-the-trade-ledger.md +42 -0
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-the-wallet.md +4 -5
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-trade-moments.md +4 -5
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading.md +4 -5
- package/dist/packages/mcp/assets/kb/docs/docs-popup-chart-buy-and-sell-markers.md +37 -0
- package/dist/packages/mcp/assets/kb/docs/docs-popup-chart-what-it-shows.md +2 -1
- package/dist/packages/mcp/assets/kb/docs/docs-screens-autotrade-paper.md +26 -0
- package/dist/packages/mcp/assets/kb/docs/docs-screens-order-plans.md +1 -1
- package/dist/packages/mcp/assets/kb/docs/docs-screens-token-screen.md +2 -0
- package/dist/packages/mcp/assets/kb/docs/docs-spectator-the-brain-view-and-the-pnl-chip.md +1 -1
- package/dist/packages/mcp/assets/kb/docs/docs-telegram-approve-one-tap-entries.md +50 -0
- package/dist/packages/mcp/assets/kb/docs/docs-telegram-control-the-commands.md +43 -0
- package/dist/packages/mcp/assets/kb/docs/docs-telegram-if-something-goes-wrong.md +30 -0
- package/dist/packages/mcp/assets/kb/docs/docs-telegram-notify-what-reaches-your-phone.md +41 -0
- package/dist/packages/mcp/assets/kb/docs/docs-telegram-set-it-up.md +47 -0
- package/dist/packages/mcp/assets/kb/docs/docs-telegram-the-record.md +26 -0
- package/dist/packages/mcp/assets/kb/docs/docs-telegram-what-it-is.md +33 -0
- package/dist/packages/mcp/assets/kb/docs/docs-telegram-what-it-will-not-do.md +31 -0
- package/dist/packages/mcp/assets/kb/docs/docs-telegram.md +23 -0
- package/dist/packages/mcp/assets/kb/docs/docs-troubleshooting-common-questions.md +1 -1
- package/dist/packages/mcp/assets/kb/docs/docs-troubleshooting-doctor-lines.md +4 -0
- package/dist/packages/mcp/assets/kb/docs/docs-voice-linux-and-windows.md +1 -1
- package/dist/packages/mcp/assets/kb/docs/docs-voice.md +1 -1
- package/dist/packages/mcp/assets/kb/docs/docs-yolo-1-replay-it-on-your-own-history.md +42 -0
- package/dist/packages/mcp/assets/kb/docs/docs-yolo-2-run-it-on-paper.md +34 -0
- package/dist/packages/mcp/assets/kb/docs/docs-yolo-3-watch-it-and-stop-it.md +32 -0
- package/dist/packages/mcp/assets/kb/docs/docs-yolo-the-rules.md +37 -0
- package/dist/packages/mcp/assets/kb/docs/docs-yolo-what-it-is.md +34 -0
- package/dist/packages/mcp/assets/kb/docs/docs-yolo-what-it-will-not-do.md +31 -0
- package/dist/packages/mcp/assets/kb/docs/docs-yolo.md +26 -0
- package/dist/packages/mcp/assets/kb/entries/autotrade.md +38 -0
- package/dist/packages/mcp/src/app-help.js +1 -1
- package/dist/packages/mcp/src/autotrade-tools.js +944 -0
- package/dist/packages/mcp/src/backtest-requests.js +71 -0
- package/dist/packages/mcp/src/engine/config.js +159 -0
- package/dist/packages/mcp/src/engine/index.js +10 -0
- package/dist/packages/mcp/src/engine/loop.js +101 -0
- package/dist/packages/mcp/src/engine/mcp-client.js +123 -0
- package/dist/packages/mcp/src/engine/ollama.js +258 -0
- package/dist/packages/mcp/src/engine/probe.js +110 -0
- package/dist/packages/mcp/src/engine/reason.js +35 -0
- package/dist/packages/mcp/src/engine/restrictions.js +111 -0
- package/dist/packages/mcp/src/index.js +7 -1
- package/dist/packages/mcp/src/ledger-tools.js +346 -0
- package/dist/packages/mcp/src/paper-agent.js +2 -0
- package/dist/packages/mcp/src/server.js +127 -19
- package/dist/packages/packs/src/backtest.js +3 -1
- package/dist/packages/popup/src/pages/chart-lib.js +134 -21
- package/dist/packages/popup/src/pages/chart.css +9 -0
- package/dist/packages/popup/src/pages/chart.html +3 -1
- package/dist/packages/popup/src/pages/chart.js +104 -7
- package/dist/packages/popup/src/protocol.js +2 -0
- package/dist/packages/popup/src/server.js +4 -0
- package/dist/packages/recorder/src/index.js +2 -0
- package/dist/packages/recorder/src/recorder.js +63 -6
- package/dist/packages/recorder/src/retention.js +100 -0
- package/dist/packages/recorder/src/schema.js +34 -1
- package/dist/packages/recorder/src/ticks.js +237 -0
- package/dist/packages/tui/src/index.js +1 -0
- package/dist/packages/tui/src/keymap.js +21 -1
- package/dist/packages/tui/src/markers.js +219 -0
- package/dist/packages/tui/src/widgets.js +149 -2
- package/package.json +2 -1
- package/dist/packages/data/src/trade/caps.js +0 -323
- package/dist/packages/data/src/trade/executor.js +0 -933
- package/dist/packages/data/src/trade/plans/executor-live.js +0 -220
- package/dist/packages/data/src/trade/rpc-exec.js +0 -229
- package/dist/packages/data/src/trade/signer/client.js +0 -197
- package/dist/packages/data/src/trade/signer/fast-wallet.js +0 -154
- package/dist/packages/data/src/trade/signer/host.js +0 -97
- package/dist/packages/data/src/trade/signer/main.js +0 -121
- package/dist/packages/data/src/trade/signer/probe-builder.js +0 -85
- package/dist/packages/data/src/trade/signer/protocol.js +0 -92
- package/dist/packages/data/src/trade/signer/service.js +0 -400
- package/dist/packages/data/src/trade/signer/sol-usd-feed.js +0 -98
- package/dist/packages/data/src/trade/sol-usd.js +0 -86
- package/dist/packages/data/src/trade/swap-build.js +0 -108
- package/dist/packages/data/src/trade/token-delta.js +0 -201
- package/dist/packages/data/vendor/solana-web3/LICENSE +0 -20
- package/dist/packages/data/vendor/solana-web3/NOTICE.md +0 -13
- package/dist/packages/data/vendor/solana-web3/index.iife.min.js +0 -20
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-a-live-ticket.md +0 -42
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-before-you-press-size-vs-caps.md +0 -34
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-devnet-signer-mainnet-token.md +0 -35
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-jupiter-rate-limits.md +0 -33
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-link-a-wallet.md +0 -32
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-live-trading-devnet-first.md +0 -30
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-mainnet.md +0 -31
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-the-live-fire-path-devnet-the-fast-wallet.md +0 -41
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-the-signer-process.md +0 -34
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-what-the-live-path-keeps.md +0 -37
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-your-first-live-trade.md +0 -41
|
@@ -5,14 +5,14 @@
|
|
|
5
5
|
// feed. Both go through the data layer's rate limiter + budget meter; neither signs, holds a key, or
|
|
6
6
|
// sends a transaction — the only trade op is `executor.execute`, a TradeExecutor the UI holds behind
|
|
7
7
|
// an interface (acceptance (d)).
|
|
8
|
-
import { SOL_MINT, lamportsToSol, rawToTokens, positionPnl,
|
|
9
|
-
import { openTicket, ticketKey, toOrder, orderValid, buyNotionalSol,
|
|
10
|
-
/** task-1368: bounds on
|
|
8
|
+
import { SOL_MINT, lamportsToSol, rawToTokens, positionPnl, withPriority, } from '../../../data/src/index.js';
|
|
9
|
+
import { openTicket, ticketKey, toOrder, orderValid, buyNotionalSol, DEFAULT_TYPEBACK_THRESHOLD_SOL, } from "../trade.js";
|
|
10
|
+
/** task-1368: bounds on a rate-limit wait ("retry in Ns"). */
|
|
11
11
|
export const RETRY_MIN_MS = 1_000;
|
|
12
12
|
export const RETRY_MAX_MS = 120_000;
|
|
13
|
-
/** When
|
|
13
|
+
/** When a rate-limit error gave no wait, assume this. */
|
|
14
14
|
export const RETRY_DEFAULT_MS = 10_000;
|
|
15
|
-
/**
|
|
15
|
+
/** A rate-limit error, if that is what `e` is: the honest wait and its own line. */
|
|
16
16
|
export function rateLimitOf(e) {
|
|
17
17
|
if (!(e instanceof Error))
|
|
18
18
|
return null;
|
|
@@ -25,14 +25,6 @@ export function rateLimitOf(e) {
|
|
|
25
25
|
const ms = typeof given === 'number' && Number.isFinite(given) && given > 0 ? given : parsed ? Number(parsed[1]) * 1000 : RETRY_DEFAULT_MS;
|
|
26
26
|
return { ms: Math.min(RETRY_MAX_MS, Math.max(RETRY_MIN_MS, ms)), message: plain };
|
|
27
27
|
}
|
|
28
|
-
/** A signer QuoteView → the SwapQuote shape the preview fill and the ticket already understand. */
|
|
29
|
-
export function quoteFromView(v) {
|
|
30
|
-
return {
|
|
31
|
-
inputMint: v.inputMint, outputMint: v.outputMint, inAmount: BigInt(v.inAmountRaw), outAmount: BigInt(v.outAmountRaw), otherAmountThreshold: BigInt(v.minOutRaw),
|
|
32
|
-
mode: 'ExactIn', slippageBps: v.slippageBps, priceImpactPct: v.priceImpactPct, route: [...v.route], platformFeeBps: null, platformFeeAmount: null,
|
|
33
|
-
usdValue: v.usdValue, contextSlot: null, source: 'jupiter-swap', fetchedAt: v.fetchedAt,
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
28
|
/** Default bound on the confirm-time quote: after this the ticket errors instead of hanging. */
|
|
37
29
|
export const CONFIRM_QUOTE_TIMEOUT_MS = 8_000;
|
|
38
30
|
/** A live PAPER trade ticket over one mint. */
|
|
@@ -57,21 +49,7 @@ export class TradeTicketLive {
|
|
|
57
49
|
confirmAbort = null;
|
|
58
50
|
/** Set when the user cancels (esc) during `filling`, so confirm() leaves the ticket in editing. */
|
|
59
51
|
cancelled = false;
|
|
60
|
-
// ---- LIVE (task-1328)
|
|
61
|
-
liveDeps;
|
|
62
|
-
livePositionRaw;
|
|
63
52
|
onSettled;
|
|
64
|
-
signerStatus = null;
|
|
65
|
-
livePlan = null;
|
|
66
|
-
liveOutcome = null;
|
|
67
|
-
liveError = null;
|
|
68
|
-
liveProbe = false;
|
|
69
|
-
planSeq = 0;
|
|
70
|
-
// ---- task-1368: rate-limited plan → wait + auto-retry (never an error phase); the signer's SOL/USD for the preflight
|
|
71
|
-
liveRetryAt = null;
|
|
72
|
-
liveRetryMsg = null;
|
|
73
|
-
retryTimer = null;
|
|
74
|
-
liveSolUsd = null;
|
|
75
53
|
constructor(dl, wallet, exec, seed, opts = {}) {
|
|
76
54
|
this.dl = dl;
|
|
77
55
|
this.wallet = wallet;
|
|
@@ -80,8 +58,6 @@ export class TradeTicketLive {
|
|
|
80
58
|
this.onChange = opts.onChange ?? (() => { });
|
|
81
59
|
this.threshold = opts.typebackThresholdSol ?? DEFAULT_TYPEBACK_THRESHOLD_SOL;
|
|
82
60
|
this.confirmTimeoutMs = opts.confirmQuoteTimeoutMs ?? CONFIRM_QUOTE_TIMEOUT_MS;
|
|
83
|
-
this.liveDeps = opts.live ?? null;
|
|
84
|
-
this.livePositionRaw = opts.livePositionRaw ?? (() => 0n);
|
|
85
61
|
this.onSettled = opts.onSettled ?? null;
|
|
86
62
|
this.decimalsKnown = typeof seed.decimals === 'number' && Number.isFinite(seed.decimals) && seed.decimals > 0;
|
|
87
63
|
this.ticket = openTicket(seed);
|
|
@@ -89,278 +65,8 @@ export class TradeTicketLive {
|
|
|
89
65
|
this.refreshQuote();
|
|
90
66
|
}
|
|
91
67
|
positionTokensRaw() {
|
|
92
|
-
if (this.ticket.mode === 'live')
|
|
93
|
-
return this.livePositionRaw(this.ticket.mint);
|
|
94
68
|
return this.wallet.position(this.ticket.mint)?.tokensRaw ?? 0n;
|
|
95
69
|
}
|
|
96
|
-
// ------------------------------------------------------------------------------------ LIVE (task-1328)
|
|
97
|
-
/** Is LIVE mode available right now? A reason string when not. */
|
|
98
|
-
liveUnavailable() {
|
|
99
|
-
if (!this.liveDeps)
|
|
100
|
-
return 'LIVE trading is not available in this run';
|
|
101
|
-
if (!this.liveDeps.linked())
|
|
102
|
-
return 'no wallet linked — /wallet link first';
|
|
103
|
-
const s = this.liveDeps.signer();
|
|
104
|
-
if (!s)
|
|
105
|
-
return 'the signer process is not available';
|
|
106
|
-
if (!s.alive)
|
|
107
|
-
return 'the signer process died — restart dexterm to trade live';
|
|
108
|
-
return null;
|
|
109
|
-
}
|
|
110
|
-
/**
|
|
111
|
-
* Flip PAPER ⇄ LIVE (the user's `L`). Entering LIVE reads the signer's status (its network + caps,
|
|
112
|
-
* which the banner shows — never the UI's own flags) and refuses when no wallet is linked or the
|
|
113
|
-
* signer is down. Leaving LIVE drops any plan.
|
|
114
|
-
*/
|
|
115
|
-
setMode(mode) {
|
|
116
|
-
if (this.ticket.phase !== 'editing')
|
|
117
|
-
return;
|
|
118
|
-
if (mode === this.ticket.mode)
|
|
119
|
-
return;
|
|
120
|
-
if (mode === 'live') {
|
|
121
|
-
const why = this.liveUnavailable();
|
|
122
|
-
if (why) {
|
|
123
|
-
this.ticket.message = why;
|
|
124
|
-
this.onChange();
|
|
125
|
-
return;
|
|
126
|
-
}
|
|
127
|
-
this.ticket.mode = 'live';
|
|
128
|
-
this.liveOutcome = null;
|
|
129
|
-
this.liveError = null;
|
|
130
|
-
this.livePlan = null;
|
|
131
|
-
this.liveProbe = false;
|
|
132
|
-
this.ticket.message = 'LIVE: ⏎ builds the plan in the signer · Y on the plan signs in Phantom';
|
|
133
|
-
void this.refreshSignerStatus();
|
|
134
|
-
}
|
|
135
|
-
else {
|
|
136
|
-
this.dropPlan();
|
|
137
|
-
this.ticket.mode = 'paper';
|
|
138
|
-
this.liveProbe = false;
|
|
139
|
-
this.ticket.message = 'PAPER';
|
|
140
|
-
}
|
|
141
|
-
this.refreshQuote();
|
|
142
|
-
this.onChange();
|
|
143
|
-
}
|
|
144
|
-
/** Re-read the signer's status (network, caps, panic). Null when it cannot be reached. */
|
|
145
|
-
async refreshSignerStatus() {
|
|
146
|
-
const s = this.liveDeps?.signer() ?? null;
|
|
147
|
-
if (!s) {
|
|
148
|
-
this.signerStatus = null;
|
|
149
|
-
return null;
|
|
150
|
-
}
|
|
151
|
-
try {
|
|
152
|
-
this.signerStatus = await s.status();
|
|
153
|
-
}
|
|
154
|
-
catch (e) {
|
|
155
|
-
this.signerStatus = null;
|
|
156
|
-
this.liveError = msg(e);
|
|
157
|
-
}
|
|
158
|
-
this.onChange();
|
|
159
|
-
return this.signerStatus;
|
|
160
|
-
}
|
|
161
|
-
/** LIVE ⏎: ask the signer to quote → build → decode → simulate the plan for this order. */
|
|
162
|
-
async planLive() {
|
|
163
|
-
const s = this.liveDeps?.signer() ?? null;
|
|
164
|
-
const my = ++this.planSeq;
|
|
165
|
-
this.livePlan = null;
|
|
166
|
-
this.liveOutcome = null;
|
|
167
|
-
this.liveError = null;
|
|
168
|
-
this.clearRetryTimer();
|
|
169
|
-
this.liveRetryAt = null;
|
|
170
|
-
this.liveRetryMsg = null;
|
|
171
|
-
this.onChange();
|
|
172
|
-
try {
|
|
173
|
-
if (!s || !s.alive)
|
|
174
|
-
throw new Error(this.liveUnavailable() ?? 'signer unavailable');
|
|
175
|
-
const ctx = this.ctx();
|
|
176
|
-
const order = toOrder(this.ticket, ctx);
|
|
177
|
-
if (!this.liveProbe && !orderValid(this.ticket, ctx))
|
|
178
|
-
throw new Error('order is no longer valid');
|
|
179
|
-
const [plan, status] = await Promise.all([
|
|
180
|
-
this.liveProbe ? s.probe() : s.plan({ mint: order.mint, symbol: order.symbol, side: order.side, decimals: order.decimals, amountRaw: order.amountRaw.toString(), slippageBps: order.slippageBps }),
|
|
181
|
-
s.status().catch(() => null),
|
|
182
|
-
]);
|
|
183
|
-
if (my !== this.planSeq) {
|
|
184
|
-
void s.drop(plan.hash).catch(() => { });
|
|
185
|
-
return;
|
|
186
|
-
} // cancelled meanwhile
|
|
187
|
-
this.signerStatus = status;
|
|
188
|
-
this.livePlan = plan;
|
|
189
|
-
if (this.ticket.phase === 'planning')
|
|
190
|
-
this.ticket.phase = 'plan';
|
|
191
|
-
}
|
|
192
|
-
catch (e) {
|
|
193
|
-
if (my !== this.planSeq)
|
|
194
|
-
return;
|
|
195
|
-
// task-1368: Jupiter rate limiting is NOT a dead end. The ticket stays in `planning`, shows the signer's own
|
|
196
|
-
// line with the countdown, retries by itself when the wait is over, and `r` retries now / esc cancels.
|
|
197
|
-
const rl = this.ticket.phase === 'planning' ? rateLimitOf(e) : null;
|
|
198
|
-
if (rl) {
|
|
199
|
-
this.liveRetryAt = this.now() + rl.ms;
|
|
200
|
-
this.liveRetryMsg = rl.message;
|
|
201
|
-
this.ticket.message = `${rl.message} · r retries now · esc cancels`;
|
|
202
|
-
this.scheduleRetry(rl.ms, my);
|
|
203
|
-
return;
|
|
204
|
-
}
|
|
205
|
-
this.liveError = msg(e);
|
|
206
|
-
this.ticket.phase = 'error';
|
|
207
|
-
this.ticket.message = `plan failed: ${this.liveError}`;
|
|
208
|
-
}
|
|
209
|
-
finally {
|
|
210
|
-
this.onChange();
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
/** task-1368: the auto-retry after a rate-limited plan. Fires only if the ticket is still waiting on that very attempt. */
|
|
214
|
-
scheduleRetry(ms, seq) {
|
|
215
|
-
this.clearRetryTimer();
|
|
216
|
-
const h = setTimeout(() => {
|
|
217
|
-
this.retryTimer = null;
|
|
218
|
-
if (this.ticket.phase === 'planning' && this.planSeq === seq && this.liveRetryAt !== null)
|
|
219
|
-
void this.planLive();
|
|
220
|
-
}, Math.max(0, ms));
|
|
221
|
-
if (typeof h.unref === 'function')
|
|
222
|
-
h.unref();
|
|
223
|
-
this.retryTimer = h;
|
|
224
|
-
}
|
|
225
|
-
clearRetryTimer() {
|
|
226
|
-
if (this.retryTimer) {
|
|
227
|
-
clearTimeout(this.retryTimer);
|
|
228
|
-
this.retryTimer = null;
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
/** task-1368: `r` while rate limited — retry the plan now instead of waiting out the countdown. No-op otherwise. */
|
|
232
|
-
retryPlan() {
|
|
233
|
-
if (this.ticket.phase !== 'planning' || this.liveRetryAt === null)
|
|
234
|
-
return;
|
|
235
|
-
void this.planLive();
|
|
236
|
-
}
|
|
237
|
-
/** Ms until the automatic retry (0 when due, null when not waiting). */
|
|
238
|
-
retryInMs() {
|
|
239
|
-
return this.liveRetryAt === null ? null : Math.max(0, this.liveRetryAt - this.now());
|
|
240
|
-
}
|
|
241
|
-
/** LIVE Y on the plan: the signer re-checks caps, opens Phantom, verifies, re-simulates, submits. */
|
|
242
|
-
async confirmLive() {
|
|
243
|
-
const s = this.liveDeps?.signer() ?? null;
|
|
244
|
-
const plan = this.livePlan;
|
|
245
|
-
try {
|
|
246
|
-
if (!s || !s.alive)
|
|
247
|
-
throw new Error(this.liveUnavailable() ?? 'signer unavailable');
|
|
248
|
-
if (!plan)
|
|
249
|
-
throw new Error('no plan to confirm');
|
|
250
|
-
const out = await s.confirm(plan.hash);
|
|
251
|
-
this.liveOutcome = out;
|
|
252
|
-
if (out.kind === 'filled') {
|
|
253
|
-
this.ticket.phase = 'filled';
|
|
254
|
-
this.ticket.message = null;
|
|
255
|
-
this.liveDeps?.onFill?.();
|
|
256
|
-
}
|
|
257
|
-
else if (out.kind === 'refused') {
|
|
258
|
-
this.ticket.phase = 'refused';
|
|
259
|
-
this.ticket.message = `${out.reason}: ${out.message}`;
|
|
260
|
-
}
|
|
261
|
-
else {
|
|
262
|
-
this.ticket.phase = 'error';
|
|
263
|
-
this.ticket.message = out.error;
|
|
264
|
-
}
|
|
265
|
-
// task-1340: the settled outcome (and only that) reaches the effects. `send-unknown` is deliberately
|
|
266
|
-
// excluded: the chain may still confirm it, so there is no verdict to show.
|
|
267
|
-
const settled = settledFromConfirm(out, this.ticket.symbol, this.ticket.mint, this.liveProbe);
|
|
268
|
-
if (settled)
|
|
269
|
-
this.settle(settled);
|
|
270
|
-
}
|
|
271
|
-
catch (e) {
|
|
272
|
-
this.liveError = msg(e);
|
|
273
|
-
this.ticket.phase = 'error';
|
|
274
|
-
this.ticket.message = `confirm failed: ${this.liveError}`;
|
|
275
|
-
this.settle({ status: 'failed', side: this.ticket.side, symbol: this.ticket.symbol, mint: this.ticket.mint, sig: null, solDelta: null, pnlSol: null, pnlPct: null, ledger: 'live', reason: this.liveError });
|
|
276
|
-
}
|
|
277
|
-
finally {
|
|
278
|
-
void this.refreshSignerStatus();
|
|
279
|
-
this.onChange();
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
/** Esc while planning: forget the in-flight plan (it is dropped when it lands), or stop a rate-limit wait. */
|
|
283
|
-
cancelPlan() {
|
|
284
|
-
if (this.ticket.phase !== 'planning')
|
|
285
|
-
return;
|
|
286
|
-
this.planSeq++;
|
|
287
|
-
this.clearRetryTimer();
|
|
288
|
-
this.liveRetryAt = null;
|
|
289
|
-
this.liveRetryMsg = null;
|
|
290
|
-
this.ticket.phase = 'editing';
|
|
291
|
-
this.ticket.message = 'plan cancelled';
|
|
292
|
-
this.onChange();
|
|
293
|
-
}
|
|
294
|
-
/**
|
|
295
|
-
* task-1368: the order's size against the signer's caps, priced at the SIGNER's SOL/USD (the preview quote carries
|
|
296
|
-
* it; the status does too). Null on PAPER, without signer status, or for the probe.
|
|
297
|
-
*/
|
|
298
|
-
preflight() {
|
|
299
|
-
if (this.ticket.mode !== 'live' || this.liveProbe)
|
|
300
|
-
return null;
|
|
301
|
-
const st = this.signerStatus;
|
|
302
|
-
if (!st)
|
|
303
|
-
return null;
|
|
304
|
-
const sizeSol = this.ticket.side === 'buy'
|
|
305
|
-
? buyNotionalSol(this.ticket, this.wallet.balance())
|
|
306
|
-
: (this.quote && this.quote.inputMint === this.ticket.mint ? lamportsToSol(this.quote.outAmount) : 0);
|
|
307
|
-
return capPreflight({
|
|
308
|
-
side: this.ticket.side, sizeSol, solUsd: this.liveSolUsd ?? st.solUsd.price,
|
|
309
|
-
perTradeUsd: st.caps.perTradeUsd, dailyUsd: st.caps.dailyUsd, spentTodayUsd: st.spentTodayUsd,
|
|
310
|
-
});
|
|
311
|
-
}
|
|
312
|
-
/** task-1368 `f`: size a LIVE buy to the cap (SOL unit). Says why when it cannot. */
|
|
313
|
-
fitToCap() {
|
|
314
|
-
const pf = this.preflight();
|
|
315
|
-
if (!pf) {
|
|
316
|
-
this.ticket.message = 'fit to cap needs the signer status (press L again to re-read it)';
|
|
317
|
-
return;
|
|
318
|
-
}
|
|
319
|
-
if (pf.fitSizeSol === null) {
|
|
320
|
-
this.ticket.message = pf.sizeUsd === null && pf.sizeSol > 0 ? 'fit to cap needs the signer\'s SOL/USD price (not available yet)' : 'nothing fits: the cap is spent for today';
|
|
321
|
-
return;
|
|
322
|
-
}
|
|
323
|
-
this.ticket.sizeUnit = 'sol';
|
|
324
|
-
this.ticket.sizeInput = String(pf.fitSizeSol);
|
|
325
|
-
this.ticket.typeback = '';
|
|
326
|
-
this.receipt = null;
|
|
327
|
-
this.liveOutcome = null;
|
|
328
|
-
this.ticket.message = `fit to cap: ${pf.fitSizeSol} SOL (≤ $${pf.capUsd.toFixed(2)} with room for fees + rent)`;
|
|
329
|
-
this.scheduleQuote(0);
|
|
330
|
-
}
|
|
331
|
-
dropPlan() {
|
|
332
|
-
const plan = this.livePlan;
|
|
333
|
-
this.livePlan = null;
|
|
334
|
-
if (plan) {
|
|
335
|
-
const s = this.liveDeps?.signer();
|
|
336
|
-
if (s?.alive)
|
|
337
|
-
void s.drop(plan.hash).catch(() => { });
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
/** Make this LIVE ticket the devnet PROBE (wrap-and-unwrap, fees only). The plan comes from the signer. */
|
|
341
|
-
startProbe() {
|
|
342
|
-
const why = this.liveUnavailable();
|
|
343
|
-
if (why)
|
|
344
|
-
return why;
|
|
345
|
-
this.ticket.mode = 'live';
|
|
346
|
-
this.liveProbe = true;
|
|
347
|
-
this.ticket.phase = 'planning';
|
|
348
|
-
this.ticket.message = 'devnet probe: building the wrap-and-unwrap plan…';
|
|
349
|
-
void this.planLive();
|
|
350
|
-
return null;
|
|
351
|
-
}
|
|
352
|
-
liveView() {
|
|
353
|
-
if (this.ticket.mode !== 'live')
|
|
354
|
-
return undefined;
|
|
355
|
-
const st = this.signerStatus;
|
|
356
|
-
return {
|
|
357
|
-
signer: st, plan: this.livePlan, outcome: this.liveOutcome, error: this.liveError,
|
|
358
|
-
linked: this.liveDeps?.linked()?.publicKey ? shortPubkey(this.liveDeps.linked().publicKey) : null, probe: this.liveProbe,
|
|
359
|
-
preflight: this.preflight(),
|
|
360
|
-
retryAt: this.liveRetryAt, retryMessage: this.liveRetryMsg,
|
|
361
|
-
devnetWarning: devnetMintWarning({ network: st?.network ?? null, probe: this.liveProbe, mint: this.ticket.mint, perTradeUsd: st?.caps.perTradeUsd, dailyUsd: st?.caps.dailyUsd }),
|
|
362
|
-
};
|
|
363
|
-
}
|
|
364
70
|
notionalSol() {
|
|
365
71
|
if (this.ticket.side === 'buy')
|
|
366
72
|
return buyNotionalSol(this.ticket, this.wallet.balance());
|
|
@@ -380,25 +86,12 @@ export class TradeTicketLive {
|
|
|
380
86
|
/** Apply a key; refetch the warm quote on a change. Returns 'confirm'/'close' for the loop. */
|
|
381
87
|
key(k) {
|
|
382
88
|
const eff = ticketKey(this.ticket, k, this.ctx());
|
|
383
|
-
if (eff === 'confirm' || eff === 'close'
|
|
89
|
+
if (eff === 'confirm' || eff === 'close')
|
|
384
90
|
this.clearQuoteTimer();
|
|
385
91
|
if (eff === 'changed') {
|
|
386
92
|
this.receipt = null;
|
|
387
|
-
this.liveOutcome = null;
|
|
388
93
|
this.scheduleQuote();
|
|
389
94
|
}
|
|
390
|
-
if (eff === 'toggle-live')
|
|
391
|
-
this.setMode(this.ticket.mode === 'live' ? 'paper' : 'live');
|
|
392
|
-
if (eff === 'fit-cap')
|
|
393
|
-
this.fitToCap();
|
|
394
|
-
if (eff === 'drop-plan')
|
|
395
|
-
this.dropPlan();
|
|
396
|
-
if (eff === 'close')
|
|
397
|
-
this.dropPlan();
|
|
398
|
-
if (eff === 'plan')
|
|
399
|
-
void this.planLive();
|
|
400
|
-
if (eff === 'confirm-live')
|
|
401
|
-
void this.confirmLive();
|
|
402
95
|
return eff;
|
|
403
96
|
}
|
|
404
97
|
clearQuoteTimer() {
|
|
@@ -438,7 +131,7 @@ export class TradeTicketLive {
|
|
|
438
131
|
/** Fetch a warm quote for the current order (debounced by a sequence guard). */
|
|
439
132
|
refreshQuote() {
|
|
440
133
|
const ctx = this.ctx();
|
|
441
|
-
if (!orderValid(this.ticket, ctx) || this.ticket.phase === 'filling'
|
|
134
|
+
if (!orderValid(this.ticket, ctx) || this.ticket.phase === 'filling') {
|
|
442
135
|
this.quote = null;
|
|
443
136
|
return;
|
|
444
137
|
}
|
|
@@ -447,17 +140,9 @@ export class TradeTicketLive {
|
|
|
447
140
|
this.loading = true;
|
|
448
141
|
this.error = null;
|
|
449
142
|
const req = { inputMint: order.side === 'buy' ? SOL_MINT : order.mint, outputMint: order.side === 'buy' ? order.mint : SOL_MINT, amount: order.amountRaw, slippageBps: order.slippageBps, mode: 'ExactIn' };
|
|
450
|
-
// task-
|
|
451
|
-
//
|
|
452
|
-
|
|
453
|
-
// priority so a user-initiated trade quote preempts the background screener/token enrichment on
|
|
454
|
-
// the shared 0.5 rps keyless `jupiter` bucket — otherwise the warm quote queues for seconds.
|
|
455
|
-
const s = this.ticket.mode === 'live' ? this.liveDeps?.signer() ?? null : null;
|
|
456
|
-
const viaSigner = s && s.alive && typeof s.quote === 'function'
|
|
457
|
-
? s.quote({ mint: order.mint, symbol: order.symbol, side: order.side, decimals: order.decimals, amountRaw: order.amountRaw.toString(), slippageBps: order.slippageBps })
|
|
458
|
-
.then((v) => { this.liveSolUsd = v.solUsd.price; return quoteFromView(v); })
|
|
459
|
-
: null;
|
|
460
|
-
(viaSigner ?? withPriority('high', () => this.dl.jupiterSwap.quote(req)))
|
|
143
|
+
// task-1387: the quote runs at `high` priority so a user-initiated trade quote preempts the background
|
|
144
|
+
// screener/token enrichment on the shared 0.5 rps keyless `jupiter` bucket — otherwise the warm quote queues for seconds.
|
|
145
|
+
withPriority('high', () => this.dl.jupiterSwap.quote(req))
|
|
461
146
|
.then((q) => { if (my !== this.seq)
|
|
462
147
|
return; this.quote = q; this.quoteAt = this.now(); this.loading = false; this.onChange(); })
|
|
463
148
|
.catch((e) => { if (my !== this.seq)
|
|
@@ -549,7 +234,7 @@ export class TradeTicketLive {
|
|
|
549
234
|
this.onChange();
|
|
550
235
|
}
|
|
551
236
|
}
|
|
552
|
-
/** The single exit for a settled outcome (paper fill
|
|
237
|
+
/** The single exit for a settled outcome (paper fill or failure). Never called with a quote. */
|
|
553
238
|
settle(tx) {
|
|
554
239
|
if (!this.onSettled)
|
|
555
240
|
return;
|
|
@@ -576,7 +261,6 @@ export class TradeTicketLive {
|
|
|
576
261
|
receipt: this.ticket.phase === 'filled' ? this.receipt : null,
|
|
577
262
|
rateLimited: this.ticket.phase === 'filling' && this.jupiterPaused(),
|
|
578
263
|
decimalsKnown: this.decimalsKnown,
|
|
579
|
-
live: this.liveView(),
|
|
580
264
|
};
|
|
581
265
|
}
|
|
582
266
|
}
|
|
@@ -586,20 +270,6 @@ export function settledFromFill(f, costBeforeLamports) {
|
|
|
586
270
|
const basis = f.side === 'sell' && costBeforeLamports !== null && costBeforeLamports > 0n ? lamportsToSol(costBeforeLamports) : null;
|
|
587
271
|
return { status: 'confirmed', side: f.side, symbol: f.symbol, mint: f.mint, sig: null, solDelta: lamportsToSol(f.solDelta), pnlSol, pnlPct: basis ? pnlSol / basis : null, ledger: 'paper' };
|
|
588
272
|
}
|
|
589
|
-
/** A signer ConfirmView → the settled outcome, or null when there is none to show (`send-unknown`, probes). */
|
|
590
|
-
export function settledFromConfirm(out, symbol, mint, probe) {
|
|
591
|
-
if (out.kind === 'send-unknown')
|
|
592
|
-
return null;
|
|
593
|
-
if (out.kind === 'filled') {
|
|
594
|
-
if (probe)
|
|
595
|
-
return null; // the devnet wrap-and-unwrap probe is not a trade
|
|
596
|
-
const f = out.fill;
|
|
597
|
-
const pnlSol = f.side === 'sell' ? lamportsToSol(BigInt(f.realizedLamports)) : 0;
|
|
598
|
-
return { status: 'confirmed', side: f.side, symbol: f.symbol || symbol, mint: f.mint || mint, sig: out.signature, solDelta: lamportsToSol(BigInt(f.solDelta)), pnlSol, pnlPct: null, ledger: 'live' };
|
|
599
|
-
}
|
|
600
|
-
const reason = out.kind === 'refused' ? `${out.reason}: ${out.message}` : out.error;
|
|
601
|
-
return { status: 'failed', side: 'buy', symbol, mint, sig: out.kind === 'send-failed' ? out.signature : null, solDelta: null, pnlSol: null, pnlPct: null, ledger: 'live', reason };
|
|
602
|
-
}
|
|
603
273
|
function safePreview(exec, order, q) {
|
|
604
274
|
try {
|
|
605
275
|
return exec.previewFill(order, q);
|
|
@@ -703,7 +373,7 @@ export class PositionsLive {
|
|
|
703
373
|
solUsd() {
|
|
704
374
|
return this.solPriceUsd;
|
|
705
375
|
}
|
|
706
|
-
/** The last DexScreener mark for a mint (SOL per token)
|
|
376
|
+
/** The last DexScreener mark for a mint (SOL per token). */
|
|
707
377
|
markOf(mint) {
|
|
708
378
|
return this.marks.get(mint) ?? null;
|
|
709
379
|
}
|
|
@@ -844,121 +514,6 @@ export class PositionsLive {
|
|
|
844
514
|
};
|
|
845
515
|
}
|
|
846
516
|
}
|
|
847
|
-
// ---------------------------------------------------------------------------------------------
|
|
848
|
-
// task-1328 item 5: LIVE positions. The signer process books confirmed real fills into its live ledger
|
|
849
|
-
// file; the UI reads that file READ-ONLY (never writes it) and serves the same PositionSource interface
|
|
850
|
-
// the paper ledger does, so the token screen's position row and the popup chart show real positions
|
|
851
|
-
// through the task-1323 selector unchanged. A CombinedPositions wraps both: live wins for a mint when
|
|
852
|
-
// held live, else paper; every HeldPosition says which ledger it came from.
|
|
853
|
-
/** Live positions from the signer's ledger file (read-only). A missing file reads as flat. */
|
|
854
|
-
export class LivePositions {
|
|
855
|
-
kind = 'live';
|
|
856
|
-
path;
|
|
857
|
-
now;
|
|
858
|
-
mark;
|
|
859
|
-
memo = new Map();
|
|
860
|
-
rowsMemo = null;
|
|
861
|
-
solUsdValue = null;
|
|
862
|
-
constructor(path, opts = {}) {
|
|
863
|
-
this.path = path;
|
|
864
|
-
this.now = opts.now ?? (() => Date.now());
|
|
865
|
-
this.mark = opts.mark ?? (() => null);
|
|
866
|
-
if (opts.solUsd)
|
|
867
|
-
this.solUsdFn = opts.solUsd;
|
|
868
|
-
}
|
|
869
|
-
solUsdFn = () => this.solUsdValue;
|
|
870
|
-
setSolPrice(p) { if (typeof p === 'number' && Number.isFinite(p) && p > 0)
|
|
871
|
-
this.solUsdValue = p; }
|
|
872
|
-
solUsd() { return this.solUsdFn(); }
|
|
873
|
-
/** All positions (open + closed) from the ledger file, memoised HELD_MEMO_MS. Unreadable → []. */
|
|
874
|
-
positions() {
|
|
875
|
-
const now = this.now();
|
|
876
|
-
if (this.rowsMemo && now - this.rowsMemo.at >= 0 && now - this.rowsMemo.at < HELD_MEMO_MS)
|
|
877
|
-
return this.rowsMemo.rows;
|
|
878
|
-
let rows = [];
|
|
879
|
-
try {
|
|
880
|
-
const l = new LiveLedger({ path: this.path, readOnly: true });
|
|
881
|
-
try {
|
|
882
|
-
rows = l.positions();
|
|
883
|
-
}
|
|
884
|
-
finally {
|
|
885
|
-
l.close();
|
|
886
|
-
}
|
|
887
|
-
}
|
|
888
|
-
catch {
|
|
889
|
-
rows = [];
|
|
890
|
-
}
|
|
891
|
-
this.rowsMemo = { at: now, rows };
|
|
892
|
-
return rows;
|
|
893
|
-
}
|
|
894
|
-
/** task-1407: the raw ledger rows (newest first, swaps only) with network + signature, for the LIVE PnL card. */
|
|
895
|
-
fills(mint, limit = 500) {
|
|
896
|
-
try {
|
|
897
|
-
const l = new LiveLedger({ path: this.path, readOnly: true });
|
|
898
|
-
try {
|
|
899
|
-
return l.trades(limit * 2).filter((r) => r.kind === 'swap' && r.mint === mint).slice(0, limit);
|
|
900
|
-
}
|
|
901
|
-
finally {
|
|
902
|
-
l.close();
|
|
903
|
-
}
|
|
904
|
-
}
|
|
905
|
-
catch {
|
|
906
|
-
return [];
|
|
907
|
-
}
|
|
908
|
-
}
|
|
909
|
-
/** Confirmed live fills (newest first) for the popup markers / history; probes excluded. */
|
|
910
|
-
records(limit = 100, mint) {
|
|
911
|
-
try {
|
|
912
|
-
const l = new LiveLedger({ path: this.path, readOnly: true });
|
|
913
|
-
try {
|
|
914
|
-
return l.records(limit, mint);
|
|
915
|
-
}
|
|
916
|
-
finally {
|
|
917
|
-
l.close();
|
|
918
|
-
}
|
|
919
|
-
}
|
|
920
|
-
catch {
|
|
921
|
-
return [];
|
|
922
|
-
}
|
|
923
|
-
}
|
|
924
|
-
held(mint) {
|
|
925
|
-
const now = this.now();
|
|
926
|
-
const m = this.memo.get(mint);
|
|
927
|
-
if (m && now - m.at >= 0 && now - m.at < HELD_MEMO_MS)
|
|
928
|
-
return m.v;
|
|
929
|
-
const p = this.positions().find((x) => x.mint === mint) ?? null;
|
|
930
|
-
const v = p ? heldFromPaper(p, this.mark(mint)) : null;
|
|
931
|
-
if (v)
|
|
932
|
-
v.kind = 'live';
|
|
933
|
-
if (this.memo.size > 64)
|
|
934
|
-
this.memo.clear();
|
|
935
|
-
this.memo.set(mint, { at: now, v });
|
|
936
|
-
return v;
|
|
937
|
-
}
|
|
938
|
-
/** task-1473 r2: mints of the open live positions (the AI-scan PnL chip). Memoised with positions(). */
|
|
939
|
-
openMints() { return this.positions().filter((p) => p.tokensRaw > 0n).map((p) => p.mint); }
|
|
940
|
-
/** Forget memoised reads (after a fill). */
|
|
941
|
-
invalidate() { this.memo.clear(); this.rowsMemo = null; }
|
|
942
|
-
}
|
|
943
|
-
/** Paper + live behind one PositionSource: live wins for a mint when held live, else paper. */
|
|
944
|
-
export class CombinedPositions {
|
|
945
|
-
kind = 'paper';
|
|
946
|
-
paper;
|
|
947
|
-
live;
|
|
948
|
-
constructor(paper, live) { this.paper = paper; this.live = live; }
|
|
949
|
-
held(mint) {
|
|
950
|
-
const l = this.live?.held(mint) ?? null;
|
|
951
|
-
if (l)
|
|
952
|
-
return l;
|
|
953
|
-
const p = this.paper.held(mint);
|
|
954
|
-
if (p)
|
|
955
|
-
p.kind = 'paper';
|
|
956
|
-
return p;
|
|
957
|
-
}
|
|
958
|
-
solUsd() { return this.paper.solUsd() ?? this.live?.solUsd() ?? null; }
|
|
959
|
-
/** task-1473 r2: every open mint, live first (the AI-scan PnL chip picks one). */
|
|
960
|
-
openMints() { return [...new Set([...(this.live?.openMints() ?? []), ...this.paper.openMints()])]; }
|
|
961
|
-
}
|
|
962
517
|
function msg(e) {
|
|
963
518
|
return e instanceof Error ? e.message : String(e);
|
|
964
519
|
}
|
|
@@ -49,7 +49,7 @@ export class WatchlistLive {
|
|
|
49
49
|
this.store.propose({ mint: c.mint, kind: 'mcap', op: '<', value: c.mcap * 0.5, note: 'half mcap vs add' });
|
|
50
50
|
proposed = 2;
|
|
51
51
|
}
|
|
52
|
-
this.store.log({ mint: c.mint, kind: 'watch', level: 'info', text: `${c.symbol} added to watchlist${c.price !== null ? `
|
|
52
|
+
this.store.log({ mint: c.mint, kind: 'watch', level: 'info', text: `${c.symbol} added to watchlist${c.mcap ? ` at ${fmtAny('mcap', c.mcap)} mcap${c.price !== null ? ` (${fmtPrice(c.price)})` : ''}` : c.price !== null ? ` at ${fmtPrice(c.price)}` : ''}` }); // task-1537: the cap first, both kept
|
|
53
53
|
this.notice = `watching $${c.symbol}${proposed ? ` · ${proposed} alert proposals (y to arm, x to dismiss)` : ' · no price or mcap yet, so no alert proposals'}`;
|
|
54
54
|
this.onChange?.();
|
|
55
55
|
return 'added';
|