Files
arbpulse_github/src/domain/entities/index.ts
T
Mauricio Barragan 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

185 lines
4.6 KiB
TypeScript

/**
* Domain types for the cross-exchange BTC arbitrage engine.
* All prices are quoted in USDT (BTC/USDT on every exchange — apples-to-apples,
* no USD/USDT basis distortion).
*/
export type ExchangeId = "kraken" | "bybit" | "okx" | "binance";
export const EXCHANGE_IDS: ExchangeId[] = ["kraken", "bybit", "okx", "binance"];
/** A single order book price level. */
export interface Level {
price: number;
qty: number;
}
/** Normalized order book for one exchange. Bids desc, asks asc. */
export interface OrderBook {
exchange: ExchangeId;
bids: Level[];
asks: Level[];
/** Local receive timestamp (ms epoch). */
recvTs: number;
/** Exchange-provided timestamp if available (ms epoch). */
exchangeTs: number | null;
}
/** Connection status of an exchange feed. */
export type FeedStatus = "connecting" | "live" | "stale" | "down";
/** Best bid/ask snapshot exposed to the UI. */
export interface BestQuote {
exchange: ExchangeId;
bid: number | null;
bidQty: number | null;
ask: number | null;
askQty: number | null;
recvTs: number | null;
status: FeedStatus;
/** ms since last update. */
ageMs: number | null;
}
/**
* Why an opportunity was or wasn't executed.
* Exhaustive union — handle every case.
*/
export type OpportunityStatus =
| "executed"
| "executed_partial"
| "rejected_fees"
| "rejected_liquidity"
| "rejected_risk"
| "rejected_flicker"
| "rejected_stale"
| "pending_confirm";
export interface Opportunity {
id: string;
ts: number;
buyExchange: ExchangeId;
sellExchange: ExchangeId;
/** Best (top-of-book) ask on the buy side, before walking depth. */
topBuyAsk: number;
/** Best (top-of-book) bid on the sell side, before walking depth. */
topSellBid: number;
/** Volume actually evaluated (BTC), after liquidity + wallet caps. */
volumeBtc: number;
/** Volume-weighted average buy price for volumeBtc. */
buyVwap: number;
/** Volume-weighted average sell price for volumeBtc. */
sellVwap: number;
grossSpread: number;
grossSpreadPct: number;
feeBuy: number;
feeSell: number;
netProfit: number;
netProfitPct: number;
status: OpportunityStatus;
reason: string;
/** True when generated by the synthetic demo injector. */
demo: boolean;
}
/** An executed (simulated) trade. */
export interface Trade {
id: string;
ts: number;
buyExchange: ExchangeId;
sellExchange: ExchangeId;
volumeBtc: number;
requestedBtc: number;
buyVwap: number;
sellVwap: number;
/** Buy VWAP after simulated latency drift. */
execBuyVwap: number;
/** Sell VWAP after simulated latency drift. */
execSellVwap: number;
feeBuy: number;
feeSell: number;
/** Net realized P&L in USDT (negative = loss). */
netProfit: number;
netProfitPct: number;
partial: boolean;
demo: boolean;
}
/** Per-exchange simulated wallet (pre-positioned inventory model). */
export interface Wallet {
exchange: ExchangeId;
usdt: number;
btc: number;
}
export interface RebalanceEvent {
id: string;
ts: number;
fromExchange: ExchangeId;
toExchange: ExchangeId;
asset: "BTC" | "USDT";
amount: number;
withdrawalFee: number;
reason: string;
}
export type CircuitState = "running" | "paused" | "tripped";
export interface EngineStats {
uptimeMs: number;
ticksProcessed: number;
opportunitiesDetected: number;
tradesExecuted: number;
tradesRejected: number;
realizedPnl: number;
consecutiveLosses: number;
circuit: CircuitState;
demoMode: boolean;
/** Average engine processing time per tick (ms). */
avgTickMs: number;
}
/** Full snapshot pushed to the dashboard over SSE. */
export interface StateSnapshot {
ts: number;
quotes: BestQuote[];
wallets: Wallet[];
stats: EngineStats;
recentOpportunities: Opportunity[];
recentTrades: Trade[];
rebalances: RebalanceEvent[];
pnlSeries: PnlPoint[];
config: PublicConfig;
}
export interface PnlPoint {
ts: number;
pnl: number;
}
/** Partial update body for PATCH /api/config. */
export interface ConfigPatch {
minNetProfitPct?: number;
maxTradeBtc?: number;
flickerConfirmMs?: number;
activeExchanges?: Partial<Record<ExchangeId, boolean>>;
}
/** Engine config surfaced to the UI (no secrets). */
export interface PublicConfig {
minNetProfitPct: number;
maxTradeBtc: number;
staleMs: number;
flickerConfirmMs: number;
latencyMs: number;
activeExchanges: Record<ExchangeId, boolean>;
defaults: {
minNetProfitPct: number;
maxTradeBtc: number;
flickerConfirmMs: number;
activeExchanges: Record<ExchangeId, boolean>;
};
takerFees: Record<ExchangeId, number>;
withdrawalFeesBtc: Record<ExchangeId, number>;
}