src/numbers/minimums.test.ts
v0.2.1 · 3.8 KB
import { describe, expect, it } from 'vitest';
import { LighterNumbersError } from './errors.js';
import { meetsMinimums, meetsMinimumsExact } from './minimums.js';
describe('meetsMinimums', () => {
it('passes the dollar gate and fails the lot gate (the 21706 case)', () => {
// A synthetic order of 0.0071 at mark ~1605 is $11.40: above $10, below the 0.01 lot minimum.
const r = meetsMinimums({ notional: 0.0071 * 1605, baseAmount: 0.0071, minBaseAmount: 0.01, minQuoteUsd: 10 });
expect(r.ok).toBe(false);
expect(r.failing).toEqual(['min_base_amount']);
});
it('passes the lot gate and fails the dollar gate', () => {
// 0.04 lots at ~$90 is $3.6: above the lot minimum, below $10.
const r = meetsMinimums({ notional: 3.6, baseAmount: 0.04, minBaseAmount: 0.04, minQuoteUsd: 10 });
expect(r.ok).toBe(false);
expect(r.failing).toEqual(['min_quote_amount']);
});
it('reports both when both fail, none when both pass', () => {
expect(meetsMinimums({ notional: 5, baseAmount: 0.001, minBaseAmount: 0.01, minQuoteUsd: 10 }).failing).toEqual([
'min_quote_amount',
'min_base_amount',
]);
expect(meetsMinimums({ notional: 16, baseAmount: 0.01, minBaseAmount: 0.01, minQuoteUsd: 10 }).ok).toBe(true);
});
it('tolerates the float product of an exact $10', () => {
const notional = 3 * 3.3333333333333335; // 10.000000000000002 or 9.999999999999998 depending on operands
expect(meetsMinimums({ notional: 0.7 * 14.285714285714286, baseAmount: 1, minQuoteUsd: 10 }).ok).toBe(true);
expect(meetsMinimums({ notional, baseAmount: 1, minQuoteUsd: 10 }).ok).toBe(true);
expect(meetsMinimums({ notional: 9.99, baseAmount: 1, minQuoteUsd: 10 }).ok).toBe(false);
});
it('treats a missing or zero minimum as "no minimum"', () => {
expect(meetsMinimums({ notional: 1, baseAmount: 0.0001 }).ok).toBe(true);
expect(meetsMinimums({ notional: 1, baseAmount: 0.0001, minBaseAmount: 0, minQuoteUsd: 0 }).ok).toBe(true);
});
it('rejects invalid input', () => {
expect(() => meetsMinimums({ notional: Number.NaN, baseAmount: 1 })).toThrow(LighterNumbersError);
expect(() => meetsMinimums({ notional: 1, baseAmount: -1 })).toThrow(LighterNumbersError);
expect(() => meetsMinimums({ notional: 1, baseAmount: 1, minQuoteUsd: -10 })).toThrow(LighterNumbersError);
});
});
describe('meetsMinimumsExact', () => {
const grid = { sizeDecimals: 4, priceDecimals: 2 };
it('does integer arithmetic on the wire values', () => {
// 0.0071 * 1605.00 = 11.3955 >= 10; 0.0071 < 0.0100
const r = meetsMinimumsExact({
...grid,
baseAmount: 71,
price: 160500,
minBaseAmount: '0.0100',
minQuoteUsd: '10.000000',
});
expect(r.failing).toEqual(['min_base_amount']);
expect(r.notional).toBeCloseTo(11.3955, 6);
expect(r.baseAmount).toBe(0.0071);
});
it('accepts an order worth exactly the minimum', () => {
// 0.0100 * 1000.00 = 10.000000
const r = meetsMinimumsExact({
...grid,
baseAmount: 100,
price: 100000,
minBaseAmount: '0.0100',
minQuoteUsd: '10.000000',
});
expect(r.ok).toBe(true);
// one tick below
const below = meetsMinimumsExact({ ...grid, baseAmount: 100, price: 99999, minQuoteUsd: '10.000000' });
expect(below.failing).toEqual(['min_quote_amount']);
});
it('handles minimums with more decimals than the grid', () => {
const r = meetsMinimumsExact({ ...grid, baseAmount: 100, price: 100000, minBaseAmount: '0.010000001' });
expect(r.failing).toEqual(['min_base_amount']);
});
it('rejects malformed input', () => {
expect(() => meetsMinimumsExact({ ...grid, baseAmount: 1.5, price: 1 })).toThrow(LighterNumbersError);
expect(() => meetsMinimumsExact({ ...grid, baseAmount: 1, price: 1, minQuoteUsd: 'ten' })).toThrow(
LighterNumbersError,
);
});
});