Skip to content
Next — unreleased

Markets

View as Markdown

There are two kinds of market, and they answer different questions.

A local market belongs to a star system and has an order book: people posting what they will buy or sell and at what price. A faction market offers goods on faction terms rather than through player orders.

const markets = await system.localMarkets.all();
const forOre = await system.localMarkets.forCargo(cargoId);

forCargo is the one you usually want: markets are per-resource, so asking “what is the market for this cargo in this system” is the natural question.

An order book is not a price. It is a set of orders, each with a quantity and a price — and the two sides are separate reads rather than one list you filter:

const buying = market.bids;
const selling = market.asks;

They are modelled apart because the data available on an order depends on its side: maker state differs between buying and selling. Flattening them would mean a single shape with half its fields undefined at any time.

The same resource can trade at different prices in different systems, and that is a feature of the game rather than stale data. Moving goods between systems where prices differ is a strategy, not an arbitrage bug.

So there is no such thing as the price of a resource. There is a price at a market, at a moment.

Joining an order book is a write: you post what you will buy or sell, at your price, from your own state at that market’s starbase. If this would be your first write, read How Atlas Kit changes the game first.

planPlaceLocalMarketOrder takes the market, your state at its starbase, and the order itself — the side, a price per unit, and a quantity, both as the same raw bigint amounts you read:

import type { PlanAuthorization } from '@aephia/atlas-kit/markets/actions';
import { planPlaceLocalMarketOrder } from '@aephia/atlas-kit/markets/actions';
const authorization = {
profile: character.profile.address,
authority: authoritySigner.address,
keyIndex: 0,
} satisfies PlanAuthorization;
const held = base.cargo.items.find((item) => item.id === market.cargo.id);
if (held !== undefined && held.quantityRaw > 0n) {
const plan = await planPlaceLocalMarketOrder(ctx, market, base, {
authorization,
side: 'ask',
priceRaw: 25_000_000n,
quantity: 1n,
});
console.table(plan.describe());
}

Selling requires holding what you sell — the snippet checks the starbase storage for the market’s resource first, which is also why placing an order starts from your starbase state rather than from the market alone. If you have no state at that starbase yet, register there first.

The planner proves what it can from current state — the market matches the starbase, the order’s numbers are valid — and the order book itself decides matching when the Plan executes. Remember the caution above: this is the one surface where other players are actively racing you, so plan against fresh reads and expect the book to have moved. Signing and executing works exactly as in Warp & subwarp.

An empty order book is normal. A market with nobody trading in it exists and returns nothing. That is not a missing read.

Prices are raw integers. Like all amounts, they need the cargo definitions to render meaningfully, and they are bigint.

Faction markets are not order books. Do not expect the same shape. They offer goods rather than matching player orders.