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.
Event-Driven Architecture
Section titled “Event-Driven Architecture”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.
Event Flow
Section titled “Event Flow”Events generally flow through the system in the following sequence:
- Integrations (e.g., Binance WS, Polymarket WS) fetch raw data and publish domain-specific events (e.g.,
MarketDataUpdated,ReferencePriceEvent) to theEventBus. - The BotStore subscribes to all events to maintain an up-to-date internal state of the bot (positions, balances, active markets).
- The TradingEngine listens for market and price events. When conditions are met, it triggers strategies.
- Strategies generate intents which eventually lead to Execution actions.
- The Execution layer publishes trading events (e.g.,
OrderPlaced,OrderFill) back to the bus. - The RiskManager monitors all events to enforce safety checks and can trigger a
KillSwitchTriggeredevent if limits are breached.
Event Reference
Section titled “Event Reference”All events share a base structure:
| Field | Type | Description |
|---|---|---|
tsMs | number | Unix timestamp in milliseconds when the event was created. |
hrTsMs | number? | High-resolution timestamp (performance.now()) for sub-millisecond precision. |
v | 1 | Version of the event schema. |
type | string | Unique identifier for the event type. |
Session Events
Section titled “Session Events”Events related to the lifecycle of the bot session.
SessionStarted
Section titled “SessionStarted”Emitted when the bot starts a new session.
| Field | Type | Description |
|---|---|---|
runId | string | Unique identifier for the current run. |
mode | "replay" | "paper" | "live" | The execution mode of the bot. |
SessionStopped
Section titled “SessionStopped”Emitted when the bot session ends.
| Field | Type | Description |
|---|---|---|
reason | string | The reason the session was stopped. |
Market Events
Section titled “Market Events”Events related to Polymarket market states and data.
MarketSelected
Section titled “MarketSelected”Emitted when a specific market is chosen for trading.
| Field | Type | Description |
|---|---|---|
marketId | string | The unique ID of the market. |
slug | string | The human-readable slug for the market. |
endTimeMs | number | Market expiration timestamp. |
upTokenId | string? | The ID for the ‘Yes/Up’ token. |
downTokenId | string? | The ID for the ‘No/Down’ token. |
MarketDataUpdated
Section titled “MarketDataUpdated”Emitted when the orderbook for a tracked market changes.
| Field | Type | Description |
|---|---|---|
marketId | string | The ID of the market. |
up | { bestBid, bestAsk } | Best bid/ask for the ‘Up’ token. |
down | { bestBid, bestAsk } | Best bid/ask for the ‘Down’ token. |
ref | object? | Optional mid-price reference data. |
Trading Events
Section titled “Trading Events”Events related to the execution of trades.
OrderPlaced
Section titled “OrderPlaced”Emitted when a new order is submitted to the exchange or simulator.
| Field | Type | Description |
|---|---|---|
marketId | string | The ID of the market. |
orderId | string | Unique 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. |
price | number | The price at which the order was placed. |
size | number | The quantity of tokens. |
reason | string | The logic or strategy reason for placing the order. |
OrderFill
Section titled “OrderFill”Emitted when an order is partially or fully filled.
| Field | Type | Description |
|---|---|---|
marketId | string | The ID of the market. |
orderId | string | The ID of the parent order. |
fillId | string | Unique identifier for this specific fill. |
price | number | The execution price of the fill. |
size | number | The quantity filled. |
feePaid | number | The transaction fee incurred. |
PositionUpdated
Section titled “PositionUpdated”Emitted when the bot’s position in a market changes.
| Field | Type | Description |
|---|---|---|
marketId | string | The ID of the market. |
upSize | number | Current net position in ‘Up’ tokens. |
downSize | number | Current net position in ‘Down’ tokens. |
Price Events
Section titled “Price Events”Events from external price or data feeds.
ReferencePriceEvent
Section titled “ReferencePriceEvent”Emitted when new price data is received from an external reference source (e.g., Binance).
| Field | Type | Description |
|---|---|---|
source | "binance" | "chainlink" | The source of the price data. |
symbol | string | The asset symbol (e.g., “BTCUSDC”). |
price | number | The current reference price. |
timing | object? | Optional high-precision timing info (exchangeTsMs, arrivalTsMs). |
Risk Events
Section titled “Risk Events”Events related to system safety and risk management.
KillSwitchTriggered
Section titled “KillSwitchTriggered”Emitted when a critical safety limit is hit, halting all trading.
| Field | Type | Description |
|---|---|---|
reason | string | The specific risk condition that triggered the kill switch. |
Recording Events
Section titled “Recording Events”Events related to the persistence of bot data.
RecordingUpdated
Section titled “RecordingUpdated”Emitted periodically to report the status of event recording.
| Field | Type | Description |
|---|---|---|
count | number | Total number of events recorded so far. |
bytes | number | Total size of the recording on disk in bytes. |
Subscribing to Events
Section titled “Subscribing to Events”You can subscribe to the event stream by providing a handler function to the EventBus.
import { eventBus } from "./core/events/eventBus";
// Define a handlerconst handleEvent = (event: BotEvent) => { if (event.type === "OrderFill") { console.log(`Order ${event.orderId} filled at ${event.price}`); }};
// Subscribeconst unsubscribe = eventBus.subscribe(handleEvent);
// Later, stop listeningunsubscribe();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.