Skip to main content
All types are implemented in Rust and exposed to Python via PyO3. Import them from horizon or horizon._horizon.

Enums

All enums support equality (==), hashing, and can be used as dict keys.
from horizon import Side, OrderSide, OrderType, TimeInForce, OrderStatus, AlertLevel, TriggerType, ContingentOrder

Side

Market side.
Side.Yes    # prediction market YES outcome
Side.No     # prediction market NO outcome
Side.Long   # equities, crypto, options (non-prediction instruments)

OrderSide

Buy or sell direction.
OrderSide.Buy
OrderSide.Sell

OrderType

OrderType.Limit
OrderType.Market

TimeInForce

TimeInForce.GTC   # Good Till Cancel (default)
TimeInForce.GTD   # Good Till Date
TimeInForce.FOK   # Fill Or Kill
TimeInForce.FAK   # Fill And Kill

OrderStatus

OrderStatus.New
OrderStatus.Submitted
OrderStatus.Accepted
OrderStatus.PartiallyFilled
OrderStatus.Filled
OrderStatus.Canceled
OrderStatus.Rejected

AlertLevel

AlertLevel.Info
AlertLevel.Warning
AlertLevel.Critical

TriggerType

Contingent order trigger type.
TriggerType.StopLoss
TriggerType.TakeProfit

AssetClass

Instrument asset class.
AssetClass.PredictionMarket
AssetClass.Equity
AssetClass.Option
AssetClass.Crypto
AssetClass.Future

OptionType

Option contract type.
OptionType.Call
OptionType.Put

Quote

A quote represents a bid/ask pair at a given size.
quote = hz.Quote(bid=0.45, ask=0.55, size=10.0)

quote.bid       # 0.45
quote.ask       # 0.55
quote.size      # 10.0
quote.spread()  # 0.10
quote.mid()     # 0.50
Helper function (bid/ask clamped to [0.01, 0.99]; returns [] if crossed):
quotes = hz.quotes(fair=0.50, spread=0.06, size=5.0)
# → [Quote(bid=0.47, ask=0.53, size=5.0)]

Market

A market definition.
# Prediction market
market = hz.Market(
    id="will-btc-hit-100k",
    name="Will BTC hit $100k?",
    slug="will-btc-hit-100k",
    exchange="polymarket",           # "polymarket", "kalshi", or "paper"
    expiry="2025-12-31",
    active=True,
    yes_token_id="123456789",        # Polymarket token ID
    no_token_id="987654321",         # Polymarket token ID
    condition_id="0xabc...",         # Polymarket condition ID
    neg_risk=True,                   # Polymarket neg-risk flag
    ticker="KXBTC-25FEB16",         # Kalshi ticker
)

market.token_id(Side.Yes)  # "123456789"
market.token_id(Side.No)   # "987654321"

# Equity
market = hz.Market(
    id="AAPL",
    name="Apple Inc.",
    exchange="alpaca",
    ticker="AAPL",
    asset_class="equity",
)
market.token_id(Side.Long)  # None (no token IDs for equities)
FieldTypeDefaultDescription
idstrrequiredMarket identifier
namestr""Display name
slugstr""URL slug
exchangestr"paper"Exchange name
expirystr or NoneNoneExpiry date
activeboolTrueWhether market is active
yes_token_idstr or NoneNonePolymarket Yes token ID
no_token_idstr or NoneNonePolymarket No token ID
condition_idstr or NoneNonePolymarket condition ID
neg_riskboolFalsePolymarket neg-risk flag
tickerstr or NoneNoneKalshi ticker
event_idstr or NoneNoneEvent ID (set when market is part of a multi-outcome event)
outcome_namestr or NoneNoneOutcome name within the event (e.g., “Trump”)
asset_classstr or NoneNoneAsset class: “prediction_market”, “equity”, “option”, “crypto”, “future”
underlyingstr or NoneNoneUnderlying symbol for derivatives (e.g., “AAPL” for AAPL options)
strike_pricefloat or NoneNoneStrike price for options
option_typestr or NoneNone”call” or “put”
multiplierfloat or NoneNoneContract multiplier (100 for US options)

Outcome

A single named outcome in a multi-outcome event. Each outcome is itself a binary contract with YES/NO tokens.
from horizon import Outcome, Side

outcome = Outcome(
    name="Trump",
    market_id="trump-wins-2024",
    yes_token_id="token_yes_123",
    no_token_id="token_no_456",
    yes_price=0.55,
)

outcome.token_id(Side.Yes)  # "token_yes_123"
outcome.token_id(Side.No)   # "token_no_456"
FieldTypeDefaultDescription
namestrrequiredOutcome name (e.g., “Trump”)
market_idstrrequiredBinary contract market ID for this outcome
yes_token_idstr or NoneNoneYES token ID
no_token_idstr or NoneNoneNO token ID
yes_pricefloat0.0Current YES price

Event

Groups multiple outcomes under a shared event/condition. Used for multi-outcome prediction markets.
from horizon import Event, Outcome

event = Event(
    id="election-2024",
    name="Who wins the 2024 election?",
    outcomes=[trump, biden, desantis],
    neg_risk=True,
    exchange="polymarket",
    condition_id="0xabc...",
)

event.outcome_count()           # 3
event.outcome_names()           # ["Trump", "Biden", "DeSantis"]
event.outcome_by_name("Trump")  # Outcome or None
event.to_markets()              # list[Market] with event_id/outcome_name set
FieldTypeDefaultDescription
idstrrequiredEvent identifier
namestrrequiredDisplay name
outcomeslist[Outcome]requiredList of outcomes
neg_riskboolFalsePolymarket neg-risk flag
exchangestr"polymarket"Exchange name
condition_idstr or NoneNonePolymarket condition ID
expirystr or NoneNoneExpiry date
See Multi-Outcome Events for full usage guide.

EventArbitrageOpportunity

Represents an arbitrage opportunity across outcomes in a multi-outcome event (when outcome prices don’t sum to 1.0).
opp.event_id        # "election-2024"
opp.exchange         # "polymarket"
opp.price_sum        # 0.97 (sum of all outcome YES prices)
opp.overround        # -0.03 (price_sum - 1.0)
opp.direction        # "buy_all" (buy all outcomes for guaranteed profit)
opp.net_edge         # 0.01 (edge after fees)
opp.is_executable    # True
FieldTypeDescription
event_idstrEvent identifier
exchangestrExchange name
price_sumfloatSum of all outcome YES prices
overroundfloatprice_sum - 1.0
directionstr"buy_all" or "sell_all"
net_edgefloatEdge after fees
is_executableboolWhether the edge exceeds fees

OrderRequest

An order request submitted to the engine.
req = hz.OrderRequest(
    market_id="will-btc-hit-100k",
    side=Side.Yes,
    order_side=OrderSide.Buy,
    size=10.0,
    price=0.55,
    order_type=OrderType.Limit,     # default
    time_in_force=TimeInForce.GTC,  # default
    post_only=True,                 # default
    token_id="123456789",           # optional, for Polymarket
    neg_risk=False,                 # optional, for Polymarket
)
FieldTypeDefaultDescription
market_idstrrequiredMarket identifier
sideSiderequiredYes, No, or Long. Use Side.Long for equities/crypto.
order_sideOrderSiderequiredBuy or Sell
sizefloatrequiredOrder size
pricefloatrequiredLimit price
order_typeOrderTypeLimitLimit or Market
time_in_forceTimeInForceGTCTime in force
post_onlyboolTruePost-only flag
token_idstr or NoneNonePolymarket token ID
neg_riskboolFalsePolymarket neg-risk flag

Order

An order with current state. Created by the engine when an OrderRequest is submitted.
order.id                # "abc123"
order.market_id         # "will-btc-hit-100k"
order.side              # Side.Yes
order.order_side        # OrderSide.Buy
order.price             # 0.55
order.size              # 10.0
order.filled_size       # 5.0
order.remaining_size    # 5.0
order.status            # OrderStatus.PartiallyFilled
order.created_at        # 1700000000.0 (unix timestamp)
order.status_reason     # None or "risk violation: ..."
order.exchange          # "polymarket"
order.amendment_count   # 0 (incremented on each successful amend)
order.is_open()         # True
FieldTypeDescription
idstrOrder ID (exchange-assigned)
market_idstrMarket identifier
sideSideYes, No, or Long
order_sideOrderSideBuy or Sell
pricefloatLimit price
sizefloatOriginal order size
filled_sizefloatSize filled so far
remaining_sizefloatRemaining unfilled size
order_typeOrderTypeLimit or Market
time_in_forceTimeInForceTime in force
statusOrderStatusCurrent status
created_atfloatUnix timestamp
status_reasonstr or NoneReason for rejection/cancel
exchangestrExchange name
amendment_countu32Number of times this order has been amended (starts at 0)

Position

A position in a market.
pos.market_id           # "will-btc-hit-100k"
pos.side                # Side.Yes
pos.size                # 10.0
pos.avg_entry_price     # 0.55
pos.realized_pnl        # 0.50
pos.unrealized_pnl      # 0.30
pos.token_id            # "123456789" or None
pos.exchange            # "polymarket"
pos.total_pnl()         # 0.80
pos.notional()          # 5.50 (size * avg_entry_price)
FieldTypeDescription
market_idstrMarket identifier
sideSideYes, No, or Long
sizefloatPosition size
avg_entry_pricefloatAverage entry price
realized_pnlfloatRealized P&L
unrealized_pnlfloatUnrealized P&L
token_idstr or NoneToken ID (Polymarket)
exchangestrExchange name
Position has no Python constructor. Positions are created internally by the engine when fills are processed. In tests, build positions via engine.process_fill().

Fill

A fill event from an exchange.
fill = hz.Fill(
    fill_id="fill_001",
    order_id="order_001",
    market_id="will-btc-hit-100k",
    side=Side.Yes,
    order_side=OrderSide.Buy,
    price=0.55,
    size=10.0,
    fee=0.01,
    timestamp=1700000000.0,
    token_id="123456789",
    exchange="polymarket",
    is_maker=False,
)
FieldTypeDefaultDescription
fill_idstrrequiredFill identifier
order_idstrrequiredAssociated order ID
market_idstrrequiredMarket identifier
sideSiderequiredYes, No, or Long
order_sideOrderSiderequiredBuy or Sell
pricefloatrequiredFill price
sizefloatrequiredFill size
feefloat0.0Fee
timestampfloat0.0Unix timestamp
token_idstr or NoneNoneToken ID
exchangestr""Exchange name
is_makerboolFalseWhether this fill was a maker (added liquidity) or taker (removed liquidity)

ContingentOrder

A contingent order (stop-loss or take-profit) that triggers when market conditions are met. Created via engine.add_stop_loss(), engine.add_take_profit(), or engine.submit_bracket().
order.id                 # "contingent_1"
order.trigger_type       # TriggerType.StopLoss
order.market_id          # "will-btc-hit-100k"
order.side               # Side.Yes
order.order_side         # OrderSide.Sell
order.size               # 10.0
order.trigger_price      # 0.45
order.trigger_pnl        # None or 5.0
order.linked_order_id    # "contingent_2" (OCO partner) or None
order.exchange           # "paper"
order.triggered          # False
order.child_order_id     # None (set after trigger)
FieldTypeDescription
idstrContingent order identifier (e.g., "contingent_1")
trigger_typeTriggerTypeStopLoss or TakeProfit
market_idstrMarket identifier
sideSideYes, No, or Long
order_sideOrderSideBuy or Sell
sizefloatOrder size to submit when triggered
trigger_pricefloatPrice threshold that activates the order
trigger_pnlfloat or NoneOptional PnL threshold (take-profit only)
linked_order_idstr or NoneOCO partner ID (set by submit_bracket)
exchangestrTarget exchange name
triggeredboolWhether this order has been triggered
child_order_idstr or NoneID of the order submitted after trigger (None until triggered)
ContingentOrder is read-only. Use engine.add_stop_loss(), engine.add_take_profit(), or engine.submit_bracket() to create contingent orders. Use engine.cancel_contingent() to remove them.

SimPosition

A position for Monte Carlo simulation input.
pos = hz.SimPosition(
    market_id="election-winner",
    side="yes",           # "yes" or "no" (case insensitive)
    size=100.0,
    entry_price=0.50,
    current_price=0.60,
)

pos.market_id      # "election-winner"
pos.side           # "yes" (always lowercased)
pos.size           # 100.0
pos.entry_price    # 0.50
pos.current_price  # 0.60
FieldTypeDescription
market_idstrMarket identifier
sidestr"yes" or "no" (lowercased automatically)
sizefloatPosition size
entry_pricefloatAverage entry price
current_pricefloatCurrent probability estimate (used as Bernoulli probability)

SimulationResult

Result of a Monte Carlo simulation. Created by hz.monte_carlo() or hz.simulate().
result = hz.monte_carlo(positions, 10000, None, 42)

result.mean_pnl          # Average PnL
result.median_pnl        # Median PnL
result.std_dev           # Standard deviation
result.var_95            # Value at Risk (5th percentile)
result.var_99            # Value at Risk (1st percentile)
result.cvar_95           # Conditional VaR (expected shortfall)
result.max_loss          # Worst scenario
result.max_gain          # Best scenario
result.win_probability   # Fraction with positive PnL
result.scenario_pnl      # list[float] - all scenario PnLs (sorted)
result.percentiles       # list[tuple[float, float]] - percentile distribution
FieldTypeDescription
mean_pnlfloatMean PnL across scenarios
median_pnlfloatMedian PnL
std_devfloatPnL standard deviation
var_95float5th percentile PnL
var_99float1st percentile PnL
cvar_95floatAverage of worst 5% scenarios
max_lossfloatMinimum scenario PnL
max_gainfloatMaximum scenario PnL
win_probabilityfloatFraction of positive-PnL scenarios
scenario_pnllist[float]All scenario PnLs (ascending)
percentileslist[tuple[float, float]]Percentile distribution
See Monte Carlo Simulation for the full guide.

EngineStatus

A snapshot of the engine’s current state.
status = engine.status()

status.running               # True
status.kill_switch_active    # False
status.kill_switch_reason    # None
status.open_orders           # 4
status.active_positions      # 2
status.total_realized_pnl    # 1.50
status.total_unrealized_pnl  # 0.30
status.daily_pnl             # 1.80
status.uptime_secs           # 3600
status.total_pnl()           # 1.80

FeedSnapshot

A snapshot of a feed’s current data (engine level).
snap = engine.feed_snapshot("btc")

snap.price       # 100250.0
snap.bid         # 100248.0
snap.ask         # 100252.0
snap.timestamp   # 1700000000.0
snap.source      # "binance_ws"
snap.volume_24h  # 50000.0

RiskConfig

Risk configuration for the engine.
config = RiskConfig(
    max_position_per_market=100.0,
    max_portfolio_notional=1000.0,
    max_daily_drawdown_pct=5.0,
    max_order_size=50.0,
    rate_limit_sustained=50,
    rate_limit_burst=300,
    dedup_window_ms=1000,
    max_position_per_event=200.0,  # Optional, None = disabled
    price_min=0.01,                # 0.01 default (prediction markets)
    price_max=0.99,                # 0.99 default (prediction markets)
)
FieldTypeDefaultDescription
max_position_per_eventfloat or NoneNoneMaximum total position across all outcomes in a registered event. None = disabled.
price_minfloat0.01Minimum valid limit-order price
price_maxfloat0.99Maximum valid limit-order price. Set to 100000 for equities.
See Risk Management and Multi-Outcome Events for detailed documentation.