Crypto Trading (Official API)¶
pyhood wraps Robinhood's official, documented Crypto Trading API. This is separate from the unofficial API used for stocks and options.
Key Differences¶
| Stocks/Options | Crypto | |
|---|---|---|
| API | Unofficial (reverse-engineered) | Official (documented) |
| Auth | OAuth + device approval | ED25519 API keys |
| Base URL | api.robinhood.com |
trading.robinhood.com |
| Rate limits | Unknown | 100 req/min, 300 burst |
| Human needed | First login + expired refresh | Never |
Setup¶
1. Generate API Keys¶
Go to robinhood.com/account/crypto on web classic and create credentials. You'll get:
- API key (starts with
rh-api-) - Public key (base64, you upload to Robinhood)
- Private key (base64, you keep secret)
You can also generate a keypair with pyhood:
from pyhood.crypto.auth import generate_keypair
private_key, public_key = generate_keypair()
print(f"Private: {private_key}") # Save securely
print(f"Public: {public_key}") # Upload to Robinhood
2. Create a Client¶
from pyhood.crypto import CryptoClient
crypto = CryptoClient(
api_key="rh-api-your-key-here",
private_key_base64="your-private-key-base64",
)
Never share your private key
Store it in an environment variable or encrypted file. Never commit it to version control.
Market Data¶
Best Bid/Ask¶
quotes = crypto.get_best_bid_ask("BTC-USD", "ETH-USD")
for quote in quotes:
print(f"{quote.symbol}: bid=${quote.bid:.2f} ask=${quote.ask:.2f}")
Estimated Price¶
Get the expected execution price including fees:
price = crypto.get_estimated_price("BTC-USD", "buy", 0.001)
print(f"Bid: ${price.bid_price:.2f}")
print(f"Ask: ${price.ask_price:.2f}")
print(f"Fee: ${price.fee:.2f}")
Trading Pairs¶
pairs = crypto.get_trading_pairs("BTC-USD", "ETH-USD")
for pair in pairs:
print(f"{pair.symbol}: min={pair.min_order_size} max={pair.max_order_size}")
Account & Holdings¶
# Get account info
account = crypto.get_account()
print(f"Account: {account.account_number}")
print(f"Buying power: ${account.buying_power:.2f}")
print(f"Fee tier: {account.fee_tier}")
# Get holdings
holdings = crypto.get_holdings(account.account_number)
for h in holdings:
print(f"{h.asset_code}: {h.quantity} (available: {h.available_quantity})")
Placing Orders¶
Market Order (by quantity)¶
order = crypto.place_order(
account_number=account.account_number,
side="buy",
order_type="market",
symbol="BTC-USD",
order_config={"asset_quantity": "0.001"},
)
print(f"Order {order.order_id}: {order.status}")
Market Order (by dollar amount)¶
order = crypto.place_order(
account_number=account.account_number,
side="buy",
order_type="market",
symbol="BTC-USD",
order_config={"notional_amount": "100.00"}, # Buy $100 of BTC
)
Limit Order¶
order = crypto.place_order(
account_number=account.account_number,
side="buy",
order_type="limit",
symbol="BTC-USD",
order_config={
"asset_quantity": "0.001",
"limit_price": "60000.00",
},
)
Managing Orders¶
# Get all orders
orders = crypto.get_orders(account.account_number)
for order in orders:
print(f"{order.symbol} {order.side} {order.status}")
# Get specific order
order = crypto.get_order(account.account_number, "order-id-here")
# Cancel an order
crypto.cancel_order("order-id-here")
Authentication Details¶
Every request is signed with ED25519:
message = f"{api_key}{timestamp}{path}{method}{body}"
signature = ed25519_sign(message, private_key)
Three headers are sent:
| Header | Value |
|---|---|
x-api-key |
Your API key |
x-signature |
Base64-encoded ED25519 signature |
x-timestamp |
Unix timestamp (valid for 30 seconds) |
pyhood handles all of this automatically.
Rate Limits¶
The official API has documented rate limits:
- 100 requests per minute per account
- 300 requests per minute burst capacity
- Token bucket with automatic refill
pyhood includes a built-in token bucket rate limiter that tracks your usage and prevents you from hitting limits.