Market Making
Examples for building a market maker with the 100x SDK.
Setup
typescript
import { HundredX, HundredXApiError } from '100x-sdk';
const sdk = await HundredX.create({
privateKey: process.env.PRIVATE_KEY!,
brokerId: Number(process.env.BROKER_ID!),
});
const MARKET_ID = 1; // ETH-USD
const SIZE = '0.5';
const SPREAD_BPS = 10; // 10 basis points each sideBasic Spread Quoting
Post a bid and ask around a mid price:
typescript
async function quoteAroundMid(midPrice: number) {
const halfSpread = midPrice * (SPREAD_BPS / 10000);
const bidPx = (midPrice - halfSpread).toFixed(2);
const askPx = (midPrice + halfSpread).toFixed(2);
// Place bid
const bid = await sdk.exchange.placeOrder({
marketId: MARKET_ID,
isBuy: true,
amount: SIZE,
price: bidPx,
orderType: 'LIMIT',
});
// Place ask
const ask = await sdk.exchange.placeOrder({
marketId: MARKET_ID,
isBuy: false,
amount: SIZE,
price: askPx,
orderType: 'LIMIT',
});
console.log(`Quoted: ${bidPx} / ${askPx}`);
return { bid, ask };
}
await quoteAroundMid(2500);Cancel-and-Replace Loop
A market maker typically refreshes quotes periodically:
typescript
async function marketMakingLoop(getPrice: () => number) {
while (true) {
// 1. Cancel all existing orders for this market
await sdk.exchange.cancelAllOrders(MARKET_ID);
// 2. Get fresh mid price
const mid = getPrice();
// 3. Place new quotes
await quoteAroundMid(mid);
// 4. Wait before refreshing
await sleep(2000);
}
}
function sleep(ms: number) {
return new Promise(resolve => setTimeout(resolve, ms));
}Inventory-Aware Skew
Shift your quotes based on current inventory to manage risk:
typescript
async function skewedQuote(midPrice: number) {
// Check current position
const result = await sdk.info.getPositions();
const position = result.positions.find(p => p.productID === MARKET_ID);
// Calculate skew: positive inventory -> widen bid, tighten ask
const inventorySize = position ? parseFloat(position.vBalanceAmount) / 1e18 : 0;
const maxInventory = 5.0;
const skewBps = (inventorySize / maxInventory) * 5;
const halfSpread = midPrice * (SPREAD_BPS / 10000);
const bidPx = (midPrice - halfSpread - midPrice * (skewBps / 10000)).toFixed(2);
const askPx = (midPrice + halfSpread - midPrice * (skewBps / 10000)).toFixed(2);
await sdk.exchange.cancelAllOrders(MARKET_ID);
await sdk.exchange.placeOrder({
marketId: MARKET_ID,
isBuy: true,
amount: SIZE,
price: bidPx,
orderType: 'LIMIT',
});
await sdk.exchange.placeOrder({
marketId: MARKET_ID,
isBuy: false,
amount: SIZE,
price: askPx,
orderType: 'LIMIT',
});
console.log(`Skewed quote: ${bidPx} / ${askPx} (inventory: ${inventorySize.toFixed(4)})`);
}Full Market Maker Example
typescript
import { HundredX, HundredXApiError } from '100x-sdk';
async function runMarketMaker() {
const sdk = await HundredX.create({
privateKey: process.env.PRIVATE_KEY!,
brokerId: Number(process.env.BROKER_ID!),
});
const MARKET_ID = 1;
const SIZE = '0.5';
const SPREAD_BPS = 10;
const REFRESH_MS = 3000;
let refPrice = 2500;
console.log(`Starting market maker for market ${MARKET_ID}`);
console.log(`Size: ${SIZE}, Spread: ${SPREAD_BPS}bps, Refresh: ${REFRESH_MS}ms`);
while (true) {
try {
// Cancel stale quotes
await sdk.exchange.cancelAllOrders(MARKET_ID);
// Place fresh quotes
const halfSpread = refPrice * (SPREAD_BPS / 10000);
const bid = (refPrice - halfSpread).toFixed(2);
const ask = (refPrice + halfSpread).toFixed(2);
await sdk.exchange.placeOrder({
marketId: MARKET_ID,
isBuy: true,
amount: SIZE,
price: bid,
orderType: 'LIMIT',
});
await sdk.exchange.placeOrder({
marketId: MARKET_ID,
isBuy: false,
amount: SIZE,
price: ask,
orderType: 'LIMIT',
});
console.log(`[${new Date().toISOString()}] ${bid} / ${ask}`);
// Check buying power
const bp = await sdk.info.getBuyingPower();
console.log(` Buying power: ${bp.totalBuyingPower}`);
} catch (error) {
if (error instanceof HundredXApiError) {
console.error(`API Error: ${error.message}`);
} else {
throw error;
}
}
await new Promise(resolve => setTimeout(resolve, REFRESH_MS));
}
}
runMarketMaker().catch(console.error);