npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@kglozhkin/orderbook-reducer

v0.1.0

Published

Pure in-memory order book reducer with birth_ts tracking. Shared between book-keeper (online) and second-bar-engine (offline) to eliminate train/serve skew.

Readme

@kglozhkin/orderbook-reducer

Чистый in-memory reducer для стакана заявок Polymarket с трекингом birth_ts каждого уровня. Не знает про NATS, Redis, файлы и эмиссию. Используется единым между:

  • book-keeper (онлайн, BOOK_KEEPER_USE_SHARED_REDUCER=true) — для проекции в Redis.
  • execution-simulator (офлайн-бэктест) — обёрнут в VirtualBook.
  • second-bar-engine (офлайн-реконструкция исторических логов) — для генерации second-bars.

Цель — устранить train/serve skew: одна и та же реализация snapshot/delta семантики на обучении и в проде.

Установка (внутри workspace)

// package.json
"dependencies": {
  "@kglozhkin/orderbook-reducer": "file:../orderbook-reducer"
}
yarn install

Пакет не публикуется на npm — это внутренняя workspace-зависимость.

Минимальный пример

import { OrderbookReducer, classifyDelta } from '@kglozhkin/orderbook-reducer';

const r = new OrderbookReducer();

// Snapshot — полное состояние книги (административная пересинхронизация).
r.applySnapshot(
  [{ price: 0.5, size: 100 }, { price: 0.49, size: 50 }],
  [{ price: 0.51, size: 80 }],
  /* ts */ 1779494400_000,
);

console.log(r.bestBid);          // { price: 0.5, size: 100 }
console.log(r.bestAsk);          // { price: 0.51, size: 80 }
console.log(r.bidCount);         // 2

// Delta — точечное изменение одного уровня. size = НОВОЕ АБСОЛЮТНОЕ значение.
const outcome = r.applyDelta('bid', 0.5, 70, 1779494400_100);
//   side: 'bid', price: 0.5, old_size: 100, new_size: 70,
//   delta_size: -30, was_birth: false, was_death: false,
//   birth_ts_died: null

const intent = classifyDelta(outcome);
// { kind: 'decrease_partial' }   // (или 'place' / 'decrease_full' / 'no_change')

// Удаление уровня:
r.applyDelta('bid', 0.49, 0, 1779494400_200);  // was_death=true, birth_ts_died присутствует

Контракт API

class OrderbookReducer

| Метод / геттер | Возвращает | |---|---| | applyDelta(side, price, new_size, ts) | DeltaOutcome | | applySnapshot(bids, asks, ts) | SnapshotOutcome | | bestBid / bestAsk (геттеры) | BestLevel \| null | | bidCount / askCount | number | | hasLevel(side, price) | boolean | | getLevel(side, price) | Readonly<Level> \| undefined | | levels(side) | IterableIterator<{ price, size, birth_ts }> |

Типы

type Side = 'bid' | 'ask';

interface PriceLevel { price: number; size: number; }
interface Level { size: number; birth_ts: number; }
interface BestLevel { price: number; size: number; }

interface DeltaOutcome {
  side: Side;
  price: number;
  old_size: number;
  new_size: number;
  delta_size: number;          // new_size - old_size, со знаком
  was_birth: boolean;          // 0 → >0 (или новая цена)
  was_death: boolean;          // >0 → 0
  birth_ts_died: number | null; // если was_death, отдаём для lifetime-метрик
}

interface SnapshotOutcome {
  displaced_count: number;     // цен, которые были в книге, но не пришли в snapshot
  preserved_count: number;     // цен с сохранённым birth_ts
  created_count: number;       // новых цен
}

type DeltaIntent =
  | { kind: 'place' }
  | { kind: 'decrease_full' }
  | { kind: 'decrease_partial' }
  | { kind: 'no_change' };

function classifyDelta(o: DeltaOutcome): DeltaIntent;

Жёсткие инварианты

  1. size в applyDelta — НОВОЕ АБСОЛЮТНОЕ значение (REPLACE-семантика). delta_size = new_size − old_size вычисляется до записи. Это обязательное требование (план §3.2).
  2. size === 0 удаляет уровень. В этой точке выдаётся was_death: true, birth_ts_died: <birth_ts уровня>.
  3. birth_ts живёт через applyDelta для уровней с size > 0. Place долил, partial decrease — birth_ts сохраняется. Только смерть (>0 → 0) обнуляет его; перерождение (0 → >0) ставит новый.
  4. applySnapshot сохраняет birth_ts для цен, которые были в книге. Новые цены получают birth_ts = ts снапшота. Цены, отсутствующие в снапшоте, удаляются молча (без эмиссии closed_level — снапшот это административное событие).
  5. bestBid / bestAsknull при пустой книге, не -Infinity / +Infinity. Это критично для gap-арифметики и band-расчётов.

Что reducer НЕ делает

  • Не знает про NATS, Redis, файлы.
  • Не делает trade-reconciliation (это решается над reducer'ом).
  • Не хранит lastTs, initialized — это забота вызывающего.
  • Не валидирует eventId идемпотентность.
  • Не фильтрует out-of-order дельты по ts.
  • Не нормирует цены к тиковой сетке (tick_size) — снаружи.

Всё перечисленное — намеренно за пределами пакета (план §3.4): reducer должен быть переиспользуем между онлайн-сервисом и офлайн-инструментами, и каждый из них добавляет нужные обвязки.

Установка для разработки

cd orderbook-reducer
yarn install
yarn build         # → dist/
yarn typecheck
yarn test          # 35 тестов: reducer + classify
yarn test:cov

После изменений запустите тесты во всех зависимых проектах:

cd ../book-keeper && yarn test
cd ../execution-simulator && yarn test
cd ../second-bar-engine && yarn test

Связанные документы