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

@moneolabs/trading

v0.4.0

Published

Execution for AI agents: quotes, slippage bounds, TWAP and bracket orders, positions.

Readme

@moneolabs/trading

Execution for AI agents: quotes, slippage bounds, TWAP and bracket orders, positions.

npm install @moneolabs/trading

An agent that can only pay is half a participant. This package gives it quotes, routing, and order types that survive being left alone overnight, with the spend guard sitting between every intent and every signature.

Use

import { createTrading, simulatedVenue } from "@moneolabs/trading";

const trading = createTrading({
  venues: [simulatedVenue({ prices: { "USDG/AAPL": 1 / 309.92 } })],
  quoteAsset: "USDG",
  guard,
});

const quote = await trading.quote({ sell: "USDG", buy: "AAPL", notional: "1500 USDG" });
const order = await trading.execute(quote, { type: "twap", window: "30m", maxSlippage: 0.003 });

const result = await order.settled();
result.status; // "filled"
result.averagePrice; // what you actually got
result.slippage; // how far that was from the quote

Routing

quote() asks every venue that can trade the pair and returns whichever gives back the most of the buy asset. Not the lowest fee, not the best headline price: the most units, after fees and impact.

await trading.quoteAll({ sell: "USDG", buy: "AAPL", notional: "1500 USDG" });
// [{ venue: "deep-pool", buyAmount: 4.8375 AAPL }, { venue: "thin-pool", buyAmount: 4.7930 AAPL }]

Order types

| Type | Behavior | | --------- | --------------------------------------------------------------------------------------------- | | market | Fills at once inside the slippage bound. Rejected, not filled worse, if the bound is missed. | | limit | Rests until the price arrives or expiresIn passes. | | twap | Slices the notional across window, so a large order stops being the reason the price moved. | | bracket | Enters at once with takeProfit and stopLoss recorded at submission. |

TWAP slices run on absolute deadlines, not "wait gap after the last fill". Filling takes time, and with relative sleeps that time is added to every remaining slice until the order runs past the window it was given.

const order = await trading.execute(quote, { type: "twap", window: "30m", slices: 6 });

order.status(); // read state without waiting
await order.cancel(); // stops early, keeps what already filled, returns "partial"

Slippage

Every order carries a bound. It is checked twice: against a fresh quote before the venue is touched, and against the achieved fill price after. Exceeding it rejects rather than filling worse.

const result = await (await trading.execute(quote, { maxSlippage: 0.003 })).settled();

result.status; // "rejected"
result.reason; // "price moved 2.00% against the quote, over the 0.30% bound. Nothing was filled."
result.fills; // []

A rejected order never reaches a venue, so it costs nothing. Under a guard, the reserved budget is released; a partially filled order settles for exactly what filled.

Positions

Cost basis moves with average cost, so selling half a position realizes half the gain.

await (await trading.execute(entry)).settled();

trading.position("AAPL");
// { quantity, averageCost, costBasis, marketValue, unrealized, realized }

trading.mark("AAPL", 317.40); // price for unrealized figures
await trading.close("AAPL"); // sell the whole position back to the quote asset
trading.realized(); // realized P&L across everything

Cost and proceeds have to land in the quote asset. Dollar-pegged assets convert by precision alone. Anything else needs a price, and silently guessing one is how a P&L number becomes fiction, so it is refused instead.

Venues

Venue is an interface with two methods, quote and fill. simulatedVenue is the reference implementation: a fixed price table, configurable fees, price impact, and drift.

simulatedVenue({
  prices: { "USDG/AAPL": 1 / 309.92 },
  feeRate: 0.0005,
  impactPerUnit: 0.00001, // price moves against larger orders
  drift: 0.02, // adverse move between quote and fill
  quoteTtlMs: 12_000,
});

Nothing in it is random. Given the same inputs it produces the same fills, which is the only way an execution test is worth running. Turn drift up to watch the slippage bound do its job.

Testing

Pass a manualClock and a thirty minute TWAP takes a millisecond.

import { manualClock } from "@moneolabs/core";

const clock = manualClock(0);
const trading = createTrading({ venues, clock });

const order = await trading.execute(quote, { type: "twap", window: "30m", slices: 6 });
await clock.advance("31m");
(await order.settled()).fills; // 6

License

MIT