Files
arbpulse/src/infrastructure/state/order-book-manager.ts
T
Mauricio BarraganandCursor 2e8744ccf0 Initial commit: Arb Pulse monolith with CI and optional Fly deploy.
Real-time BTC cross-exchange arbitrage detection (Kraken, Bybit, OKX, Binance)
with React dashboard, GitHub Actions CI, and documented Fly.io deploy workflow.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-08 21:04:53 -06:00

54 lines
1.5 KiB
TypeScript

import { config } from "../config/config.js";
import {
EXCHANGE_IDS,
type BestQuote,
type ExchangeId,
type FeedStatus,
type OrderBook,
} from "../../domain/entities/index.js";
import type { IQuoteBook } from "../../domain/ports/ports.js";
export class OrderBookManager implements IQuoteBook {
private books = new Map<ExchangeId, OrderBook>();
update(book: OrderBook): void {
this.books.set(book.exchange, book);
}
getBook(exchange: ExchangeId): OrderBook | undefined {
return this.books.get(exchange);
}
isFresh(exchange: ExchangeId, now: number): boolean {
const book = this.books.get(exchange);
if (!book) return false;
return now - book.recvTs <= config.staleMs;
}
private statusFor(book: OrderBook | undefined, now: number): FeedStatus {
if (!book) return "connecting";
const age = now - book.recvTs;
if (age > config.staleMs * 3) return "down";
if (age > config.staleMs) return "stale";
return "live";
}
bestQuotes(now: number): BestQuote[] {
return EXCHANGE_IDS.map((exchange) => {
const book = this.books.get(exchange);
const topBid = book?.bids[0];
const topAsk = book?.asks[0];
return {
exchange,
bid: topBid?.price ?? null,
bidQty: topBid?.qty ?? null,
ask: topAsk?.price ?? null,
askQty: topAsk?.qty ?? null,
recvTs: book?.recvTs ?? null,
status: this.statusFor(book, now),
ageMs: book ? now - book.recvTs : null,
};
});
}
}