Repository (clone / issues / PRs): github.com/dex-original/ai-trading-agent
Keywords: trading-bot ai-trading openrouter lighter lighter-xyz perpetuals llm llm-agent tool-calling prisma postgresql bun typescript express react vite vercel-ai-sdk crypto bitcoin ethereum altcoin algorithmic-trading automated-trading quant quantitative fintech audit telemetry positions risk open-source defi research crypto-bot autonomous-agent streaming llm openapi portfolio dashboard invocations-timeseries prisma-studio cors rest-api javascript esm bun-runtime
Disclaimer: Automated trading carries significant financial risk. This software is provided for educational and experimental use. You are solely responsible for API keys, position sizing, capital at risk, and compliance with laws in your jurisdiction. Never trade funds you cannot afford to lose.
- Why this project is useful
- What you get
- Prerequisites
- Quick start
- How a single cycle works
- Database models and tool types
- Important: position side handling
- Optional dashboard API and UI
- Project layout
- Tech stack
- Troubleshooting
- Useful tips
- License
This agent is useful when you want a repeatable, observable loop between market data, an LLM, and a small set of exchange actions—without building that plumbing from scratch every time.
| What it helps with | Why that matters |
|---|---|
| Prompt + data assembly | Each run merges candlestick-derived signals (intraday and longer horizon), balances, positions, and invocation count into one prompt (prompt.ts). You reuse the pipeline and only tune strategy text or markets. |
| Multi-model experimentation | Add rows under Models with different openRoutermodelName strings to compare models on similar conditions, or route multiple Lighter accounts from one process, without duplicating the runner. |
| Auditing and review | Responses and tool usage land in PostgreSQL (Invocations, ToolCalls), which is useful for debugging behavior, measuring how often the model opens vs. flattens, and tracing what was decided when. |
| Guardrailed automation | The model does not get arbitrary API access—it only invokes the trading tools wired in code, which is useful for limiting blast radius compared to unrestricted agents. |
| Hands-off scheduling | A fixed cadence (every 5 minutes after start) removes the need to manually trigger runs when you already trust your prompt and sizing rules. |
Useful for: researchers comparing LLMs on trading prompts, builders prototyping Lighter + OpenRouter flows, and operators who want logs and database-backed history alongside automation.
The implementation here targets Lighter and OpenRouter, but the shape of the project is easy to reuse in many environments:
| Context | How it extends |
|---|---|
| Other exchanges & venues | The same loop—scheduled run → enriched prompt → constrained tools → persisted audit—maps to perpetuals, spots, or simulated/mock adapters if you swap the exchange layer (createPosition, cancelOrder, market data fetchers) for your APIs. |
| Education & labs | Universities and coding bootcamps use this style of repo to teach tool-calling, risk disclosure, and observable agents without students wiring raw websocket trading from day one. |
| Product & fintech prototyping | Teams can demo “AI-assisted execution” internally: keep PostgreSQL telemetry and prompts, stub orders in staging or paper flows, then harden gateway rules before any real capital. |
| LLM evaluation & research | Any provider reachable through OpenRouter (or by substituting the AI SDK provider) lets you compare models on the same indicator snapshot and record outcomes in one database. |
| Compliance-minded workflows | Immutable-style logs of model output + tool calls support post-hoc review—useful in regulated or internal-trading settings where you must show what the system did and when. |
| Home labs & VPS | A small self-hosted Bun process fits low-cost servers or Raspberry Pi-class boxes for experimentation, monitoring, or personal alerting (with firewall and secret hygiene). |
Across these cases, wide reuse comes from separating strategy text (prompt.ts), data assembly, narrow tools, and storage—you can transplant that split into quant stacks, alerting bots, or research harnesses beyond crypto.
| Capability | Summary |
|---|---|
| Multi-model orchestration | Each row in Models drives its own scheduler pass with a distinct OpenRouter model name and Lighter credentials. |
| Rich context each run | 5‑minute and 4‑hour signals (mid price, EMA20, MACD), open positions, and portfolio totals are injected into the prompt. |
| Auditable actions | Invocations and tool calls (createPosition, closeAllPosition-style closes) are stored for review. |
| Periodic execution | The agent cycle runs automatically every 5 minutes once started. |
- Bun ≥ 1.x (recommended: match the version you use elsewhere in your stack).
- PostgreSQL database reachable from your machine or server.
- OpenRouter API key for the models you intend to call.
- Lighter API key (and associated
accountIndex) for each automated account configured inModels.
bun installCreate an environment file (for example .env) in this directory with at minimum:
| Variable | Required | Purpose |
|---|---|---|
DATABASE_URL |
Yes | PostgreSQL connection string used by Prisma. |
OPENROUTER_API_KEY |
Yes | Authenticates requests to OpenRouter from the AI SDK provider. |
Generate the Prisma client and apply migrations (from this directory):
bunx prisma migrate deployOr during development:
bunx prisma migrate devPopulate the Models table with one row per logical trader: each needs a unique name, OpenRouter routing string (openRoutermodelName), lighterApiKey, and accountIndex. Empty state means nothing runs—you must insert at least one valid record via your preferred SQL GUI, script, or Prisma Studio (bunx prisma studio) before expecting activity.
bun run index.tsOn startup and every five minutes afterward, the process loads every Models row and invokes invokeAgent for each. Logs include the enriched prompt body for observability—ensure logging does not violate your confidentiality policy in production environments.
| Goal | Command |
|---|---|
| Install deps | bun install |
| Apply DB migrations | bunx prisma migrate deploy (or migrate dev) |
| Generate Prisma client only | bunx prisma generate |
| Browse DB | bunx prisma studio |
| Run agent loop only | bun run index.ts |
| Run HTTP dashboard API | bun run backend.ts (needs same DATABASE_URL; port 3000) |
| Run frontend UI | cd frontend && npm install && npm run dev |
- Indicators — For each configured market (e.g. SOL, ZEC, HYPE), the agent fetches short- and medium-term candles and summarizes mid prices, EMA20, and MACD.
- State — It pulls portfolio value, available balance, and open positions tied to the Lighter credentials for that model.
- LLM turn — A trading prompt (
prompt.ts) is filled with placeholders and sent to OpenRouter streaming through the AI SDK (streamText). - Tools — If the model calls tools, executions are persisted under
InvocationsandToolCalls, and invocation counts update on the correspondingModelsrow.
Strategy text and risk rules are defined in prompt.ts; adjust them there if you change markets or risk appetite.
Prisma schema: prisma/schema.prisma; client output: generated/prisma.
| Model | Purpose |
|---|---|
| Models | One row per automated profile: name (unique), openRoutermodelName (OpenRouter model id), lighterApiKey, accountIndex, invocationCount. |
| Invocations | One row per agent run: response (final model text after streaming completes), timestamps. |
| ToolCalls | Rows linked to an invocation: toolCallType + JSON metadata. |
| PortfolioSize | Time series of netPortfolio strings per model (used by the optional /performance API). |
ToolCallType enum values: CREATE_POSITION, CLOSE_POSITION (close-all flow).
In index.ts, the createPosition tool handler inverts the model’s requested side relative to the LONG / SHORT enum sent by the LLM (the code comment states this is intentional: the executed side is the opposite of what the model chose). If you fork this repo, audit this line before live use—either remove the inversion or align your prompt so intended economics match execution.
| Component | How to run (typical) | Role |
|---|---|---|
| HTTP API | bun run backend.ts (from repo root, same env as the agent) |
Serves JSON on port 3000: GET /performance (cached portfolio history), GET /invocations?limit=N (recent runs with tool calls, limit ≤ 200). |
| Frontend | cd frontend && npm install && npm run dev |
Vite dev server; point API calls at http://localhost:3000 (or your deployed backend). |
The agent loop and the backend are separate processes—run both if you want the UI; run only index.ts if you only need automation and Prisma storage.
| Path / area | Role |
|---|---|
index.ts |
Entry point: 5-minute setInterval loop and invokeAgent (also runs main() once at startup). |
backend.ts |
Express + CORS: /performance, /invocations. |
prompt.ts |
System prompt template and trading constraints. |
markets.ts |
Symbol → Lighter market metadata. |
prisma/schema.prisma |
Models, Invocations, ToolCalls, PortfolioSize. |
stockData.ts, openPositions.ts, createPosition.ts, cancelOrder.ts |
Market data and exchange-side effects. |
frontend/ |
React dashboard (optional). |
- Runtime: Bun
- AI:
@openrouter/ai-sdk-provider,ai(Vercel AI SDK) - Data: Prisma Client (generated under
generated/prisma) + PostgreSQL - API (optional): Express 5, CORS
| Symptom | What to check |
|---|---|
| Nothing runs on schedule | Models table is empty or migration not applied; verify bunx prisma migrate deploy and at least one valid row. |
| OpenRouter or DB errors on startup | OPENROUTER_API_KEY, DATABASE_URL; Postgres reachable from the host. |
| Lighter auth / position errors | lighterApiKey and accountIndex match the account; markets.ts symbol keys match Lighter. |
Backend returns empty invocations |
Agent must have run at least once; check Prisma Invocations in Studio. |
| Frontend cannot reach API | CORS is enabled on backend.ts; ensure the frontend’s fetch URL matches where Express listens (default 3000). |
- Inspect history — Use
bunx prisma studioto browseInvocationsandToolCallswhen you need to see past model outputs and which tools actually ran. - Tune strategy without redeploying logic — Most behavioral rules live in
prompt.tsandmarkets.ts; adjust copy, markets, or constraints there while keeping the same execution path. - Dry-run mindset — Even with logging, treat small account sizes and clear stop rules as essential; the agent is a tool, not a guarantee of profit.
License for this repository is unspecified; confirm with the repository owner before redistributing or using in commercial settings.