An LLM-driven crypto trading bot. It pulls market and sentiment data on a schedule, asks a language model for a trade decision, runs that decision through hard-coded risk controls, and either executes it or asks you to approve it. It ships with a backtesting engine, a Next.js dashboard, and an optional Telegram bot.
The honest answer: just for fun. This is a project in a domain where I have no prior business knowledge at all, built to see how it goes. Treat it as an experiment, not a get-rich scheme.
This software is provided for educational and research purposes only. It is not financial advice. Cryptocurrency trading carries substantial risk of loss; you can lose some or all of your capital. The authors and contributors make no warranty as to the correctness, reliability, or profitability of this software and accept no liability for any financial losses, missed trades, exchange errors, or damages of any kind arising from its use. You are solely responsible for your own trading decisions, for securing your exchange API keys, and for complying with the laws and tax obligations of your jurisdiction. Always run with
PAPER=trueuntil you fully understand the system. By using this software you accept all risk.
- LLM trade evaluation: decisions from OpenAI or Anthropic models, with confidence calibration, an adversarial critic, and a lessons ledger.
- Customizable decision loop: feed in your own external data sources and shape the agent's style and prompt to steer it wherever you want.
- Risk management: per-trade risk sizing, a daily loss limit, a max-open-positions cap, a minimum-confidence gate, and an auto-trade size threshold above which a trade needs human approval.
- Exits: trailing stops, tiered take-profit, and partial take-profit.
- Backtesting: replay historical candles with fill simulation, slippage, and fees; runs are persisted and streamed to the dashboard.
- Web dashboard: Next.js UI for positions, trades, signals, decisions, narration, and settings.
- Telegram bot: optional
/pause/resume/status/capitalcommands and inline approve/reject prompts for trades that exceed the auto threshold. - Paper trading:
PAPER=truesimulates fills so you can run the whole system without touching a real exchange.
At the heart of moon-trader is a decision loop you can shape to your liking. On every cycle it gathers inputs, hands them to the LLM, runs the verdict through the risk controls, and then executes or asks for approval. Two parts are fully in your hands:
- External sources. Plug in extra market, sentiment, or on-chain data feeds and they become part of the context the model reasons over. The more (and better) the signals, the more informed each decision.
- Agent style and prompt. Tune the system prompt and persona to steer the bot wherever you want: cautious scalper, patient swing trader, or reckless moonshot chaser. This also makes it delightfully easy to lose money, so steer responsibly.
A pnpm + Turborepo monorepo:
| Package | Stack | Responsibility |
|---|---|---|
packages/api |
NestJS | Trading loop, LLM evaluation, backtesting, persistence, Telegram bot, HTTP API |
packages/web |
Next.js, React Query | Dashboard UI |
Inside packages/api/src:
core/: pure, dependency-free trading logic (capital guard, position tracker, order manager, trading engine).trading/: the live NestJS wiring aroundcore/(scheduler, data loader, cycle runner).llm/: provider clients and the evaluation cycle.backtest/: historical replay and fill simulation.http/: REST controllers consumed by the dashboard.telegram/: bot lifecycle, commands, trade-approval prompts.
State is persisted to PostgreSQL via Prisma.
- Node.js 20+
- pnpm 10+
- Docker (for the local PostgreSQL instance)
pnpm install
cp .env.example .env # then fill in your keys (see Configuration below)pnpm dev runs docker compose up -d --wait first (via the predev script),
which starts PostgreSQL. Apply the database schema:
pnpm --filter @trader/api db:generate
pnpm --filter @trader/api exec prisma migrate deploypnpm devThis starts the API and the web dashboard via Turborepo. By default:
- API:
http://127.0.0.1:4000(loopback only) - Web:
http://localhost:3000
All configuration is via .env (see .env.example for the full list).
Key variables:
| Variable | Purpose |
|---|---|
PAPER |
true simulates fills; false places real orders. Keep true until you are sure. |
BINANCE_API_KEY / BINANCE_SECRET |
Exchange credentials (only needed for live trading). |
LLM_PROVIDER |
openai or anthropic. |
OPENAI_API_KEY / ANTHROPIC_API_KEY |
LLM credentials. |
DATABASE_URL |
PostgreSQL connection string. |
TOTAL_CAPITAL |
Capital the bot manages. |
AUTO_TRADE_LIMIT |
Trades at or below this size execute automatically; larger ones need approval. |
API_AUTH_TOKEN |
Optional. Required bearer token for state-changing API routes (see Security). |
WEB_ORIGIN |
Allowed CORS origin for the API (default http://localhost:3000). |
The bot defaults to paper trading. Before going live:
- Run with
PAPER=truelong enough to trust the behaviour. - Create exchange API keys with trade-only permissions and no withdrawal access, and restrict them to your server's IP.
- Set
PAPER=falseand start with capital you can afford to lose.
pnpm test # run the vitest suite
pnpm typecheck # type-check all packagesThe API binds to 127.0.0.1 only and has no authentication by default; this
is safe for a local single-machine setup. Do not expose it beyond loopback
without setting API_AUTH_TOKEN. See SECURITY.md for details
and for how to report vulnerabilities.
See CONTRIBUTING.md. By participating you agree to the Code of Conduct.
MIT © Thanasis Gliatis
