Skip to content

Events System

The Hydra is built on an event-driven architecture. This design decouples data ingestion, trading logic, and execution, allowing the system to remain responsive and easily observable.

At the heart of the system is a central Event Bus. Components interact by publishing and subscribing to typed events rather than through direct method calls. This pattern provides several benefits:

  • Decoupling: The components providing market data do not need to know which strategies are currently active.
  • Observability: Every action, from a price update to a trade execution, is emitted as an event that can be logged, monitored, or recorded.
  • Persistence: All events can be serialized to disk (typically in JSON Lines format) to provide a complete audit trail.
  • Replayability: Recorded event logs can be replayed through the system to verify strategy behavior deterministically.

Events generally flow through the system in the following sequence:

  1. Integrations (e.g., Binance WS, Polymarket WS) fetch raw data and publish domain-specific events (e.g., MarketDataUpdated, ReferencePriceEvent) to the EventBus.
  2. The BotStore subscribes to all events to maintain an up-to-date internal state of the bot (positions, balances, active markets).
  3. The TradingEngine listens for market and price events. When conditions are met, it triggers strategies.
  4. Strategies generate intents which eventually lead to Execution actions.
  5. The Execution layer publishes trading events (e.g., OrderPlaced, OrderFill) back to the bus.
  6. The RiskManager monitors all events to enforce safety checks and can trigger a KillSwitchTriggered event if limits are breached.

All events share a base structure:

FieldTypeDescription
tsMsnumberUnix timestamp in milliseconds when the event was created.
hrTsMsnumber?High-resolution timestamp (performance.now()) for sub-millisecond precision.
v1Version of the event schema.
typestringUnique identifier for the event type.

Events related to the lifecycle of the bot session.

Emitted when the bot starts a new session.

FieldTypeDescription
runIdstringUnique identifier for the current run.
mode"replay" | "paper" | "live"The execution mode of the bot.

Emitted when the bot session ends.

FieldTypeDescription
reasonstringThe reason the session was stopped.

Events related to Polymarket market states and data.

Emitted when a specific market is chosen for trading.

FieldTypeDescription
marketIdstringThe unique ID of the market.
slugstringThe human-readable slug for the market.
endTimeMsnumberMarket expiration timestamp.
upTokenIdstring?The ID for the ‘Yes/Up’ token.
downTokenIdstring?The ID for the ‘No/Down’ token.

Emitted when the orderbook for a tracked market changes.

FieldTypeDescription
marketIdstringThe ID of the market.
up{ bestBid, bestAsk }Best bid/ask for the ‘Up’ token.
down{ bestBid, bestAsk }Best bid/ask for the ‘Down’ token.
refobject?Optional mid-price reference data.

Events related to the execution of trades.

Emitted when a new order is submitted to the exchange or simulator.

FieldTypeDescription
marketIdstringThe ID of the market.
orderIdstringUnique identifier assigned to the order.
side"BUY" | "SELL"Whether the order is a buy or sell.
token"UP" | "DOWN"Which token the order is for.
pricenumberThe price at which the order was placed.
sizenumberThe quantity of tokens.
reasonstringThe logic or strategy reason for placing the order.

Emitted when an order is partially or fully filled.

FieldTypeDescription
marketIdstringThe ID of the market.
orderIdstringThe ID of the parent order.
fillIdstringUnique identifier for this specific fill.
pricenumberThe execution price of the fill.
sizenumberThe quantity filled.
feePaidnumberThe transaction fee incurred.

Emitted when the bot’s position in a market changes.

FieldTypeDescription
marketIdstringThe ID of the market.
upSizenumberCurrent net position in ‘Up’ tokens.
downSizenumberCurrent net position in ‘Down’ tokens.

Events from external price or data feeds.

Emitted when new price data is received from an external reference source (e.g., Binance).

FieldTypeDescription
source"binance" | "chainlink"The source of the price data.
symbolstringThe asset symbol (e.g., “BTCUSDC”).
pricenumberThe current reference price.
timingobject?Optional high-precision timing info (exchangeTsMs, arrivalTsMs).

Events related to system safety and risk management.

Emitted when a critical safety limit is hit, halting all trading.

FieldTypeDescription
reasonstringThe specific risk condition that triggered the kill switch.

Events related to the persistence of bot data.

Emitted periodically to report the status of event recording.

FieldTypeDescription
countnumberTotal number of events recorded so far.
bytesnumberTotal size of the recording on disk in bytes.

You can subscribe to the event stream by providing a handler function to the EventBus.

import { eventBus } from "./core/events/eventBus";
// Define a handler
const handleEvent = (event: BotEvent) => {
if (event.type === "OrderFill") {
console.log(`Order ${event.orderId} filled at ${event.price}`);
}
};
// Subscribe
const unsubscribe = eventBus.subscribe(handleEvent);
// Later, stop listening
unsubscribe();

The EventBus also maintains a small history of recent events, which can be retrieved using getHistory(). This is useful for initializing UI components or calculating metrics on startup.