Skip to content
markpaper

src/orders/orders.test.ts

v0.1.0 · 5.5 KB

Download file
import { describe, expect, it } from 'vitest';
import { decToString, parseDec } from '../numbers/index.js';
import { cancelTruth, createWriteMemory } from '../pending/index.js';
import { fixtureFill, fixtureOrder } from '../testing/fixtures.js';
import { clampIocPrice, fullCloseSize, iocFill, rejectScope } from './index.js';

describe('order witnesses and pending memory', () => {
  it('uses sent quantity and cumulative remainder, not last execution quantity', () => {
    const report = iocFill({
      symbol: 'BTC-USD',
      cloid: fixtureOrder().cloid!,
      orderId: fixtureOrder().orderId,
      sent: '0.38',
      side: 'BUY',
      events: [
        fixtureOrder({ status: 'FILLED', qty: '0.14', remaining: '0.24' }),
        fixtureOrder({ status: 'FILLED', qty: '0.24', remaining: '0' }),
      ],
      fills: [],
    });
    expect(report.quantity).toBe('0.38');
  });
  it('deduplicates trade ids and uses the conservative witness', () => {
    const fill = fixtureFill({ qty: '0.18' });
    expect(
      iocFill({
        symbol: 'BTC-USD',
        cloid: fixtureOrder().cloid!,
        orderId: fixtureOrder().orderId,
        sent: '0.38',
        side: 'BUY',
        events: [fixtureOrder({ status: 'FILLED', remaining: '0' })],
        fills: [fill, fill],
      }).quantity,
    ).toBe('0.18');
  });
  it('refuses fill evidence for a different symbol even with a matching client id', () => {
    expect(
      iocFill({
        symbol: 'BTC-USD',
        cloid: fixtureOrder().cloid!,
        orderId: fixtureOrder().orderId,
        sent: '0.38',
        side: 'BUY',
        events: [],
        fills: [fixtureFill({ symbol: 'ETH-USD' })],
      }),
    ).toMatchObject({ confirmed: false, quantity: '0' });
  });
  it('does not interpret IOC terminal remaining zero as a fill', () => {
    expect(
      iocFill({
        symbol: 'BTC-USD',
        cloid: fixtureOrder().cloid!,
        orderId: fixtureOrder().orderId,
        sent: '0.38',
        side: 'BUY',
        events: [fixtureOrder({ status: 'IOC_CANCELLED', remaining: '0' })],
        fills: [],
      }).confirmed,
    ).toBe(false);
  });
  it('ceil quantizes a full close and uses only fresh bands', () => {
    expect(decToString(fullCloseSize(parseDec('-0.381')!, parseDec('0.02')!))).toBe('0.4');
    expect(
      decToString(clampIocPrice(parseDec('200')!, 'BUY', parseDec('0.25')!, { min: '80', max: '180', fresh: false })),
    ).toBe('200');
    expect(
      decToString(clampIocPrice(parseDec('200')!, 'BUY', parseDec('0.25')!, { min: '80', max: '180.1', fresh: true })),
    ).toBe('180');
  });
  it('distinguishes partial execution from successful cancellation', () => {
    expect(cancelTruth(fixtureOrder({ status: 'CANCELLED', remaining: '0.2' }), { fillsSeen: false }).verdict).toBe(
      'not_cancelled',
    );
    expect(cancelTruth(fixtureOrder({ status: 'FILLED', remaining: '0.2' }), { fillsSeen: false }).verdict).toBe(
      'not_final',
    );
    expect(cancelTruth(fixtureOrder({ status: 'CANCELLED' }), { fillsSeen: false }).verdict).toBe('cancelled');
  });
  it('never unlocks unknown fill from a lagging empty read or absent history', async () => {
    const memory = createWriteMemory({
      echoTtlMs: 80,
      readAfterWriteMs: 30,
      unknownLockMs: 70,
      unknownLockGtcMs: 100,
      failedHistoryLockMs: 170,
      canExpire: () => false,
    });
    memory.noteUnknown({
      cloid: 'ef'.repeat(16),
      symbol: 'BTC-USD',
      side: 'BUY',
      kind: 'ioc',
      quantity: '0.38',
      sentAt: 1,
    });
    expect(
      await memory.resolveUnknowns(
        { openOrders: async () => ({ orders: [], complete: true }), historicByCloid: async () => null },
        1000,
      ),
    ).toEqual([]);
    expect(memory.iocLock('BTC-USD')).toBeDefined();
    expect(
      await memory.resolveUnknowns(
        {
          openOrders: async () => ({ orders: [], complete: true }),
          historicByCloid: async () => {
            throw new Error('Unavailable');
          },
        },
        2000,
      ),
    ).toEqual([]);
  });
  it('injects early acknowledged rows and masks a cancelled stale row', () => {
    const memory = createWriteMemory({
      echoTtlMs: 80,
      readAfterWriteMs: 30,
      unknownLockMs: 70,
      unknownLockGtcMs: 100,
      failedHistoryLockMs: 170,
      canExpire: () => false,
    });
    const row = fixtureOrder();
    memory.notePlaced(row, 10);
    expect(memory.applyEcho([], 20, 20)).toHaveLength(1);
    memory.noteCancelled(row.orderId, 25);
    expect(memory.applyEcho([row], 30, 30)).toHaveLength(0);
  });
  it('keeps margin rejection scope symbol-specific except account margin', () => {
    expect(rejectScope('FAILED_MARGIN_CHECK')).toBe('account');
    expect(rejectScope('REJECTED_OPEN_INTEREST_LIMIT')).toBe('symbol');
  });
  it('keeps an unknown intent locked on a contradictory side or order id', () => {
    const memory = createWriteMemory({
      echoTtlMs: 80,
      readAfterWriteMs: 30,
      unknownLockMs: 70,
      unknownLockGtcMs: 100,
      failedHistoryLockMs: 170,
      canExpire: () => false,
    });
    const row = fixtureOrder();
    memory.noteUnknown({
      cloid: row.cloid!,
      symbol: row.symbol,
      side: 'BUY',
      kind: 'gtc',
      quantity: row.qty,
      sentAt: 1,
      orderId: row.orderId,
    });
    expect(memory.resolveUnknownByEvent({ ...row, side: 'SELL' })).toBeNull();
    expect(memory.resolveUnknownByEvent({ ...row, orderId: '20000000-0000-4000-8000-000000000003' })).toBeNull();
    expect(memory.unknownIntents()).toHaveLength(1);
  });
});
All files