npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

sealion-sim

v0.1.0

Published

Multi-agent market simulation framework on Mastra + bun:sqlite. Pluggable price simulators, matching engine, and LLM-driven traders.

Readme

Sealion

Multi-agent market simulation framework for traders. Built on Mastra so you can pick any LLM provider Mastra supports (OpenAI, Anthropic, Google, DeepSeek, Groq, Mistral, xAI, OpenRouter, Ollama, etc.) and gain Memory / Workflows / Scorers / Observability for free. Persistence via bun:sqlite.

⚠️ Bun-only. Sealion uses bun:sqlite directly. Node.js is not supported — install Bun ≥ 1.1.

Install

bun add sealion-sim
import {
  ActionType,
  TraderGraph,
  LLMAction,
  TradingAgent,
  TraderProfile,
  make,
  spotPreset,
} from "sealion-sim";

const traders = new TraderGraph();
traders.addAgent(
  new TradingAgent({
    agentId: 0,
    profile: new TraderProfile({ handle: "alice", initialCash: 10_000 }),
    model: "openai/gpt-4o-mini", // or anthropic/, google/, groq/, deepseek/...
  }),
);

const env = make({
  traders,
  market: spotPreset({ symbol: "BTC/USDT" }),
  databasePath: "./data/sim.db",
});

await env.reset();
await env.step(new Map([[traders.getAgent(0), new LLMAction()]]));
await env.close();

Mental model

                    ┌──────────────────────────────────────┐
                    │             Scenario                 │
                    │  market + pricer + traders + policy  │
                    └───────────────┬──────────────────────┘
                                    │ .run()
                                    ▼
       ┌──────────────────────────────────────────────────────┐
       │                     SealionEnv                       │
       │            reset / step / close lifecycle            │
       └───────┬───────────────────────────────────┬──────────┘
               │ tools dispatch                    │ pricer.next() each step
               ▼                                   ▼
   ┌────────────────────┐               ┌────────────────────┐
   │  TradingAgent      │ ──Channel──▶ │  Exchange          │
   │  (Mastra Agent)    │ ◀───────────  │  + MatchingEngine  │
   │  + MarketMakerBot  │               │  + Risk gate       │
   └────────────────────┘               │  + SQLite          │
                                        └────────────────────┘

TraderGraph API:

graph.addAgent(agent);
graph.removeAgent(agent);
graph.getAgent(agentId);
graph.getAgents(); // → Array<[id, agent]>
graph.getAgents([0, 1, 2]); // filter by ids
graph.hasAgent(agentId);
graph.getNumNodes();
// copy-trade edges (optional):
graph.addEdge(leaderId, followerId, ratio);
graph.removeEdge(followerId);
graph.getEdges(); // → [leaderId, followerId, ratio]
graph.getNumEdges();
graph.getFollowers(leaderId);
graph.getLeader(followerId);
graph.isLeader(agentId);
graph.isCopying(agentId);

Folder layout

src/
├── environment/
│   ├── env.ts                         SealionEnv (reset/step/close)
│   ├── env-action.ts                  ManualAction / LLMAction
│   └── make.ts                        make() factory
├── trading-agent/
│   ├── agent.ts                       TradingAgent (wraps Mastra Agent)
│   ├── agent-action.ts                Mastra createTool() per action
│   ├── agent-environment.ts           Per-agent prompt/data view
│   ├── agent-graph.ts                 TraderGraph (nodes + copy-trade edges)
│   ├── agents-generator.ts            ARCHETYPES + factories
│   └── market-maker-bot.ts            Rule-based auto-quoting bot
├── platform/
│   ├── platform.ts                    Exchange (matching + dispatch)
│   ├── channel.ts                     Actor mailbox (FIFO per agent)
│   ├── database.ts                    SQLite schema + helpers
│   ├── matching-engine.ts             Price-time priority + self-trade prevention
│   ├── pricer.ts                      8 price-process simulators
│   ├── typing.ts                      ActionType / OrderSide / etc.
│   └── config/trader-info.ts          TraderProfile + persona blocks
├── clock/clock.ts                     SandboxClock
├── testing/show-db.ts                 printDbContents
├── scenarios/scenario.ts              High-level orchestrator
├── markets/presets.ts                 spot / perp / equity / custom
├── evals/scorers.ts                   Mastra scorer factories (PnL, persona)
├── mastra-integration.ts              collectMastraAgents, observability config
└── metrics.ts                         Sharpe, max DD, FIFO win rate

Pick any model

Anything Mastra's model router supports — string-shorthand "provider/model":

new TradingAgent({ ..., model: "openai/gpt-4o-mini" });
new TradingAgent({ ..., model: "anthropic/claude-sonnet-4.5" });
new TradingAgent({ ..., model: "google/gemini-2.0-flash" });
new TradingAgent({ ..., model: "groq/llama-3.3-70b-versatile" });
new TradingAgent({ ..., model: "deepseek/deepseek-chat" });
new TradingAgent({ ..., model: "openrouter/meta-llama/llama-3.1-405b" });
new TradingAgent({ ..., model: "ollama/llama3.1" });
// ...100+ providers via Mastra

Or pass an AI SDK LanguageModel instance, or any Mastra MastraModelConfig.

Mastra integration (built-in)

Memory — opt-in journaling per trader

import { Memory } from "@mastra/memory";

new TradingAgent({
  agentId: 0,
  profile,
  model: "openai/gpt-4o-mini",
  memory: new Memory({ options: { lastMessages: 20, observationalMemory: true } }),
});

Studio — observability + scorers + experiments

import { Mastra } from "@mastra/core";
import { LibSQLStore } from "@mastra/libsql";
import { Observability } from "@mastra/observability";
import { collectMastraAgents, sealionObservabilityConfig } from "sealion-sim";

export const mastra = new Mastra({
  agents: collectMastraAgents(traders),
  storage: new LibSQLStore({ url: "file:./mastra.db" }),
  observability: new Observability(sealionObservabilityConfig({})),
});

Studio menampilkan setiap trade decision, tool call, token usage, dan trace.

Scorers — built-in trading evals

import { createPnLScorer, createPersonaConsistencyScorer } from "sealion-sim";

const pnl = createPnLScorer({ baselineEquity: 10_000, targetEquity: 15_000 });
const result = await pnl.run({
  db: env.exchange.db,
  agentId: 0,
  startingCash: 10_000,
});
// → { score: 0.42, reason: "...", metadata: { totalReturnPct, sharpe, maxDrawdownPct, ... } }

Bisa juga di-attach langsung ke TradingAgent:

new TradingAgent({
  ...,
  scorers: {
    pnl: { scorer: pnl, sampling: { type: "ratio", rate: 1 } },
  },
});

Trading actions (15)

ActionType.PLACE_LIMIT_ORDER; // { side, price, size }
ActionType.PLACE_MARKET_ORDER; // { side, size }
ActionType.CANCEL_ORDER; // { order_id }
ActionType.CANCEL_ALL_ORDERS; // {}
ActionType.GET_ORDERBOOK; // { depth? }
ActionType.GET_RECENT_TRADES; // { limit? }
ActionType.GET_ACCOUNT; // {}  → cash, position, avg, P&L, equity
ActionType.GET_OPEN_ORDERS; // {}
ActionType.DO_NOTHING; // {}
ActionType.COPY_TRADE; // { leader_id, ratio }
ActionType.UNFOLLOW; // {}
ActionType.SHARE_SIGNAL; // { content, symbol?, bias? }
ActionType.GET_SIGNALS; // { limit? }
ActionType.INTERVIEW; // { prompt, response }

Default subsets: DEFAULT_TRADER_ACTIONS, SOCIAL_TRADER_ACTIONS, SOCIAL_PLUS_TRADING_ACTIONS.

Pluggable price simulators

All deterministic given a seed.

new ConstantPrice({ price: 100, steps: 50 });
new RandomWalk({ start: 100, sigma: 1, drift: 0.01, seed: 42 });
new GBM({ start: 50_000, mu: 0.0001, sigma: 0.02, seed: 42 });
new MeanReversion({ start: 100, mu: 100, theta: 0.1, sigma: 1, seed: 42 });
new Replay({ ticks: [{ price: 100 }, { price: 101 }, ...] });
new JumpDiffusion({ base: gbm, jumpProb: 0.05, jumpStd: 0.1 });
new Composite([calmRegime, volatileRegime]);
new Scripted({ base, shocks: [{ atStep: 50, multiplier: 0.85 }] });

Market presets (no global default)

spotPreset({ symbol: "BTC/USDT" });
perpPreset({ symbol: "BTC-PERP" });
equityPreset({ symbol: "AAPL" });
customMarket({ symbol, baseAsset, quoteAsset, tickSize, lotSize, takerFeeBps, makerFeeBps });

High-level harness — Scenario

import { Scenario, GBM, Scripted, spotPreset, makeMarketMaker } from "sealion-sim";

const traders = new TraderGraph();
traders.addAgent(makeMarketMaker({ agentId: 0, cash: 1_000_000, position: 100 }));
traders.addAgent(new TradingAgent({ ... }));

const sc = new Scenario({
  market: spotPreset({ symbol: "BTC/USDT" }),
  databasePath: "./data/sim.db",
  fresh: true,
  traders,
  pricer: new Scripted({
    base: new GBM({ start: 50_000, mu: 0, sigma: 0.02, seed: 1 }),
    shocks: [{ atStep: 50, multiplier: 0.85 }], // -15% flash crash
  }),
  steps: 100,
  decideAction: (agent, ctx) => myStrategy(agent, ctx),
});

const result = await sc.run();
// → { steps, metrics: Map<id, Metrics>, accounts, env }

Examples

bun run examples/spot-manual.ts          # manual orders, no LLM
bun run examples/position-sim.ts         # hold a position, watch P&L vs GBM
bun run examples/scenario-flash-crash.ts # scripted -15% shock
bun run examples/copy-trade.ts           # leader fill → follower mirror
bun run examples/backtest.ts             # Replay synthetic OHLCV
OPENAI_API_KEY=sk-... bun run examples/spot-llm.ts

Lihat examples/README.md untuk overview tiap demo.

Quality of life

bun run lint           # oxlint
bun run lint:fix
bun run format         # oxfmt --write
bun run format:check
bun run typecheck      # tsc --noEmit
bun run check          # format + lint + typecheck
bun test               # 26 tests covering engine, copy-trade, pricers, risk, scenarios

Catatan desain

  • No global defaultsMarketSpec selalu eksplisit lewat preset.
  • Lazy LLM agent — Mastra Agent cuma diinstansiasi saat aksi LLM dipakai, jadi sim pure-manual tidak butuh API key.
  • Single-writer SQLite — semua mutasi diserialisasikan oleh Exchange.runLoop() lewat Channel.
  • Self-trade prevention — matching engine otomatis exclude order dari agent yang sama.
  • Cached mark price — invalidasi otomatis pada injectPrice / fill.
  • Skip read-only traceGET_* actions tidak nge-spam trace table.
  • FIFO win-ratecomputeMetrics pair fills properly bukan running-avg approximation.
  • Apa pun bisa disimulasikan — harga, posisi, regime shift, copy-trade, news shock, multi-LLM benchmark — semua dari building blocks yang sama.

License

Apache-2.0.