| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495 |
- import { describe, expect, it, vi } from 'vitest';
- import { OrderRouter } from '../packages/execution/src/orderRouter';
- import type { Order, OrderBook } from '../packages/domain/src/types';
- const sampleBook: OrderBook = {
- bids: [{ px: 100, sz: 1 }],
- asks: [{ px: 100.5, sz: 1 }],
- ts: Date.now()
- };
- describe('OrderRouter', () => {
- const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
- it('sends limit order within slip guard', async () => {
- const send = vi.fn(async (order: Order) => ({ id: order.clientId }));
- const router = new OrderRouter(send, () => sampleBook, { maxBps: 100 });
- const order: Order = {
- clientId: 'o-1',
- symbol: 'BTC',
- side: 'buy',
- px: 100.55,
- sz: 0.1,
- tif: 'GTC'
- };
- const id = await router.sendLimit(order);
- expect(id).toMatch(uuidRegex);
- expect(send).toHaveBeenCalledWith(expect.objectContaining({ clientId: id }));
- expect(send).toHaveBeenCalledTimes(1);
- });
- it('rejects orders exceeding slip guard', async () => {
- const send = vi.fn(async (order: Order) => ({ id: order.clientId }));
- const router = new OrderRouter(send, () => sampleBook, { maxBps: 10 });
- const order: Order = {
- clientId: 'o-2',
- symbol: 'BTC',
- side: 'buy',
- px: 102,
- sz: 0.1,
- tif: 'GTC'
- };
- await expect(router.sendLimit(order)).rejects.toThrow(/slippage/);
- expect(send).not.toHaveBeenCalled();
- });
- it('rejects post-only orders that would cross', async () => {
- const send = vi.fn(async (order: Order) => ({ id: order.clientId }));
- const router = new OrderRouter(send, () => sampleBook, { maxBps: 100 });
- const order: Order = {
- clientId: 'o-3',
- symbol: 'BTC',
- side: 'buy',
- px: 100.5,
- sz: 0.1,
- tif: 'GTC',
- postOnly: true
- };
- await expect(router.sendLimit(order)).rejects.toThrow(/post-only/);
- expect(send).not.toHaveBeenCalled();
- });
- it('throttles orders based on min interval and enforces unique client ids', async () => {
- const send = vi.fn(async (order: Order) => ({ id: order.clientId }));
- const router = new OrderRouter(send, () => sampleBook, { maxBps: 100, minIntervalMs: 10 });
- const orderA: Order = {
- clientId: 'o-4',
- symbol: 'BTC',
- side: 'buy',
- px: 100.4,
- sz: 0.1,
- tif: 'GTC'
- };
- const orderB: Order = { ...orderA, clientId: 'o-5', px: 100.45 };
- await router.sendLimit(orderA);
- expect(send).toHaveBeenCalledTimes(1);
- const start = Date.now();
- await router.sendLimit(orderB);
- const elapsed = Date.now() - start;
- expect(send).toHaveBeenCalledTimes(2);
- expect(elapsed).toBeGreaterThanOrEqual(8);
- await expect(router.sendLimit(orderB)).rejects.toThrow(/duplicate clientId/);
- });
- });
|