diff --git a/README.md b/README.md index e28c05a..93dfa99 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,12 @@ curl -fsSL https://github.com/discountry/ritmex-bot/raw/refs/heads/main/setup.sh 切换到 GRVT 时,将 `EXCHANGE=grvt` 并补齐 `GRVT_API_KEY`、`GRVT_API_SECRET`、`GRVT_SUB_ACCOUNT_ID` 等变量;详情见 `.env.example`。 +> 提示:你也可以通过命令行参数临时指定交易所(优先级高于环境变量): +> ```bash +> bun run index.ts --exchange grvt +> bun run index.ts -e lighter +> ``` + ## 常用命令 ```bash bun run index.ts # 启动 CLI(默认) @@ -90,6 +96,13 @@ bun run index.ts --strategy maker --silent # 启动做市策略 bun run index.ts --strategy offset-maker --silent # 启动偏移做市策略 ``` +如需同时指定交易所,可叠加 `--exchange/-e`(将覆盖 `.env` 中的 `EXCHANGE`/`TRADE_EXCHANGE`): + +```bash +bun run index.ts --exchange grvt --strategy maker --silent +bun run index.ts -e lighter -s offset-maker --silent +``` + ### 项目内置脚本 `package.json` 提供了便捷脚本: diff --git a/README_en.md b/README_en.md index 56e6d35..5d2c50f 100644 --- a/README_en.md +++ b/README_en.md @@ -69,6 +69,12 @@ The most important settings shipped in `.env.example` are summarised below: To trade on GRVT, set `EXCHANGE=grvt` and populate `GRVT_API_KEY`, `GRVT_API_SECRET`, `GRVT_SUB_ACCOUNT_ID`, plus any optional overrides documented in `.env.example`. +> Tip: you can temporarily override the exchange via CLI flags (takes precedence over environment): +> ```bash +> bun run index.ts --exchange grvt +> bun run index.ts -e lighter +> ``` + ## Common Commands ```bash bun run index.ts # Launch the CLI @@ -87,6 +93,13 @@ bun run index.ts --strategy maker --silent # Maker engine bun run index.ts --strategy offset-maker --silent # Offset maker engine ``` +Combine with `--exchange/-e` to explicitly choose the venue (overrides `EXCHANGE`/`TRADE_EXCHANGE` from `.env`): + +```bash +bun run index.ts --exchange grvt --strategy maker --silent +bun run index.ts -e lighter -s offset-maker --silent +``` + ### Package scripts Convenience aliases are exposed in `package.json`: diff --git a/src/cli/args.ts b/src/cli/args.ts index 17347af..68685c3 100644 --- a/src/cli/args.ts +++ b/src/cli/args.ts @@ -4,6 +4,7 @@ export interface CliOptions { strategy?: StrategyId; silent: boolean; help: boolean; + exchange?: "aster" | "grvt" | "lighter"; } const STRATEGY_VALUES = new Set(["trend", "maker", "offset-maker"]); @@ -36,6 +37,19 @@ export function parseCliArgs(argv: string[] = process.argv.slice(2)): CliOptions } continue; } + if (arg.startsWith("--exchange=")) { + const value = arg.split("=", 2)[1] ?? ""; + assignExchange(options, value); + continue; + } + if (arg === "--exchange" || arg === "-e") { + const value = argv[i + 1]; + if (value) { + assignExchange(options, value); + i += 1; + } + continue; + } } return options; @@ -51,12 +65,23 @@ function assignStrategy(options: CliOptions, raw: string): void { } } +function assignExchange(options: CliOptions, raw: string): void { + const normalized = raw.trim().toLowerCase(); + if (!normalized) return; + if (normalized === "aster" || normalized === "grvt" || normalized === "lighter") { + options.exchange = normalized as CliOptions["exchange"]; + } else if (normalized === "gravity" || normalized === "grav" || normalized === "grv") { + options.exchange = "grvt"; + } +} + export function printCliHelp(): void { // eslint-disable-next-line no-console - console.log(`Usage: bun run index.ts [--strategy ] [--silent]\n\n` + + console.log(`Usage: bun run index.ts [--strategy ] [--exchange ] [--silent]\n\n` + `Options:\n` + ` --strategy, -s Automatically start the specified strategy without the interactive menu.\n` + ` Aliases: offset, offset-maker for the offset maker engine.\n` + + ` --exchange, -e Choose exchange. Overrides EXCHANGE/TRADE_EXCHANGE environment variables.\n` + ` --silent, -q Reduce console output. When used with --strategy, runs in silent daemon mode.\n` + ` --help, -h Show this help message.\n`); } diff --git a/src/index.tsx b/src/index.tsx index 84f3812..5f7dace 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -4,9 +4,17 @@ import { App } from "./ui/App"; import { setupGlobalErrorHandlers } from "./runtime-errors"; import { parseCliArgs, printCliHelp } from "./cli/args"; import { startStrategy } from "./cli/strategy-runner"; +import { resolveExchangeId } from "./exchanges/create-adapter"; setupGlobalErrorHandlers(); const options = parseCliArgs(); +// If user specifies --exchange, override environment-based resolution for this process +if (options.exchange) { + // Ensure downstream calls to resolveExchangeId() pick the CLI value. + // We set both common env keys respected by resolveExchangeId. + process.env.EXCHANGE = options.exchange; + process.env.TRADE_EXCHANGE = options.exchange; +} if (options.help) { printCliHelp(); diff --git a/src/ui/App.tsx b/src/ui/App.tsx index d969a76..11de91b 100644 --- a/src/ui/App.tsx +++ b/src/ui/App.tsx @@ -4,6 +4,7 @@ import { TrendApp } from "./TrendApp"; import { MakerApp } from "./MakerApp"; import { OffsetMakerApp } from "./OffsetMakerApp"; import { loadCopyrightFragments, verifyCopyrightIntegrity } from "../utils/copyright"; +import { resolveExchangeId } from "../exchanges/create-adapter"; interface StrategyOption { id: "trend" | "maker" | "offset-maker"; @@ -40,16 +41,23 @@ export function App() { const [selected, setSelected] = useState(null); const copyright = useMemo(() => loadCopyrightFragments(), []); const integrityOk = useMemo(() => verifyCopyrightIntegrity(), []); + const exchangeId = useMemo(() => resolveExchangeId(), []); + const strategies = useMemo(() => { + if (exchangeId === "lighter") { + return STRATEGIES.filter((s) => s.id !== "trend"); + } + return STRATEGIES; + }, [exchangeId]); useInput( (input, key) => { if (selected) return; if (key.upArrow) { - setCursor((prev) => (prev - 1 + STRATEGIES.length) % STRATEGIES.length); + setCursor((prev) => (prev - 1 + strategies.length) % strategies.length); } else if (key.downArrow) { - setCursor((prev) => (prev + 1) % STRATEGIES.length); + setCursor((prev) => (prev + 1) % strategies.length); } else if (key.return) { - const strategy = STRATEGIES[cursor]; + const strategy = strategies[cursor]; if (strategy) { setSelected(strategy); } @@ -75,7 +83,7 @@ export function App() { 请选择要运行的策略 使用 ↑/↓ 选择,回车开始,Ctrl+C 退出。 - {STRATEGIES.map((strategy, index) => { + {strategies.map((strategy, index) => { const active = index === cursor; return (