Code Along: Manual Orders
Place orders by hand with hz.connect(), no pipeline needed
Not everything needs a pipeline. Sometimes you just want to buy 10 shares of AAPL and check your balance. hz.connect() gives you a direct handle to a venue — paper or live — with simple buy/sell/flatten methods.
This is the imperative API. No strategies, no signals, no risk checks, no portfolio optimization. Just you and the order book.
Step 1. Connect to a paper venue
import horizon as hz
ex = hz.connect("paper", initial_cash_usd=100_000)
That’s it. ex is an ImperativeClient connected to a paper trading venue with $100k starting cash. No API keys, no broker accounts. Everything runs locally.
Step 2. Place a limit buy
order = ex.buy("AAPL", qty=10, limit=185.0)
print(order)
VenueOrder(id='p1', market_id='AAPL', side='buy', quantity=10, price=185.0, status='new')
This places a limit order to buy 10 shares of AAPL at $185. The order gets ID p1 (paper venue IDs are p1, p2, p3, …).
The order status is new — it’s resting in the paper venue’s book. In a backtest, the run loop ticks prices through the venue and fills matching orders. In standalone imperative use like this, limit orders sit forever until you cancel them or feed a crossing price.
For immediate fills, use market orders:
order = ex.buy("AAPL", qty=10, market=True)
print(order.status) # "filled"
Market orders fill immediately at the last known price plus slippage.
Step 3. Sell some back
sell_order = ex.sell("AAPL", qty=5, limit=190.0)
print(sell_order)
VenueOrder(id='p2', market_id='AAPL', side='sell', quantity=5, price=190.0, status='new')
If the buy from step 2 was a market order and filled, you now hold 10 shares and have a resting sell for 5 of them.
Step 4. Check your state
# What positions do I hold?
positions = ex.positions()
for p in positions:
print(f" {p.market_id}: {p.quantity} shares")
# How much cash do I have?
balance = ex.balance()
print(f"Cash: ${balance.available_usd:,.2f}")
# What orders are still resting?
orders = ex.open_orders()
for o in orders:
print(f" {o.id}: {o.side} {o.quantity} {o.market_id} @ {o.price}")
# What fills happened?
fills = ex.fills()
for fill in fills:
print(f" Filled: {fill.side} {fill.quantity} {fill.market_id} @ {fill.price}")
ex.positions()returns a list ofVenuePositionobjects — everything you currently hold.ex.balance()returns aVenueCapitalobject withavailable_usd,total_usd, etc.ex.open_orders()returns all resting (unfilled) orders.ex.fills()drains the fill queue — once you read them, they’re consumed.
Step 5. Close a position
# Close all AAPL
ex.flatten("AAPL")
print(ex.positions()) # AAPL is gone
flatten() sends a market order in the opposite direction of your current position. If you’re long 10 shares, it sells 10 at market.
Step 6. The nuclear option
# Close everything, all markets
ex.flatten_all()
Flattens every position across every market. Use when you want to go completely flat.
Step 7. Context manager (recommended)
The cleanest pattern wraps everything in a with block. close() is called automatically on exit:
with hz.connect("paper", initial_cash_usd=100_000) as ex:
ex.buy("AAPL", qty=10, market=True)
ex.buy("MSFT", qty=5, market=True)
print("Positions:", ex.positions())
print("Balance:", ex.balance())
ex.flatten_all()
print("After flatten:", ex.positions())
Step 8. Other asset classes
The imperative API has helpers for prediction markets, perpetuals, and options:
with hz.connect("paper", initial_cash_usd=100_000) as ex:
# Prediction markets
ex.buy_prediction(
market="polymarket:trump-2028",
qty=100,
limit=0.45,
side="yes",
)
# Perpetual futures
ex.buy_perp(
"hyperliquid:BTC-PERP",
qty=0.1,
leverage=3,
limit=95_000,
)
# Options
ex.buy_option(
underlying="AAPL",
strike=180,
expiry="2025-01-17",
right="call",
qty=5,
limit=3.50,
)
Each helper sets the appropriate asset class metadata so the venue knows how to handle the order.
Step 9. Modify and cancel
with hz.connect("paper", initial_cash_usd=100_000) as ex:
order = ex.buy("AAPL", qty=10, limit=180.0)
# Change price and quantity
ex.amend(order.id, new_quantity=20, new_price=179.0)
# Cancel a specific order
ex.cancel(order.id)
# Cancel all orders on a market
ex.cancel_all(market_id="AAPL")
# Cancel everything
ex.cancel_all()
When to use this vs hz.run()
The imperative API and the pipeline serve different purposes:
hz.connect() | hz.run() | |
|---|---|---|
| Signals | None. You decide what to trade. | Strategy emits signals. |
| Sizing | You pick the quantity. | Kelly/Carver/EqualWeight decides. |
| Risk checks | None. No stops, no drawdown guards. | Full risk pipeline. |
| Attribution | None. No per-strategy tracking. | Per-strategy P&L attribution. |
| Best for | Manual trading, scripts, one-off orders | Systematic strategies, backtests |
If you want the full pipeline — features, signals, risk enforcement, portfolio optimization — use hz.run(). If you want to place a specific order right now and don’t need any of that machinery, use hz.connect().
Full file
# manual_orders.py
import horizon as hz
def main():
with hz.connect("paper", initial_cash_usd=100_000) as ex:
# Buy some stocks
ex.buy("AAPL", qty=10, market=True)
ex.buy("MSFT", qty=5, market=True)
ex.buy("NVDA", qty=3, market=True)
# Check state
print("=" * 50)
print("POSITIONS")
for p in ex.positions():
print(f" {p.market_id}: {p.quantity} shares")
print()
print(f"BALANCE: ${ex.balance().available_usd:,.2f}")
# Partial sell
ex.sell("AAPL", qty=5, market=True)
print()
print("After selling 5 AAPL:")
for p in ex.positions():
print(f" {p.market_id}: {p.quantity} shares")
# Flatten one name
ex.flatten("MSFT")
print()
print("After flattening MSFT:")
for p in ex.positions():
print(f" {p.market_id}: {p.quantity} shares")
# Flatten everything
ex.flatten_all()
print()
print("After flatten_all:")
print(f" Positions: {len(ex.positions())}")
print(f" Balance: ${ex.balance().available_usd:,.2f}")
if __name__ == "__main__":
main()
Expected output
==================================================
POSITIONS
AAPL: 10 shares
MSFT: 5 shares
NVDA: 3 shares
BALANCE: $9x,xxx.xx
After selling 5 AAPL:
AAPL: 5 shares
MSFT: 5 shares
NVDA: 3 shares
After flattening MSFT:
AAPL: 5 shares
NVDA: 3 shares
After flatten_all:
Positions: 0
Balance: $~100,000
Exact dollar amounts depend on the paper venue’s simulated prices.