Getting Started
View SourcePrerequisites
- Elixir 1.14+
- An Alpaca Markets account (sign up free)
- API keys from the Alpaca dashboard
Installation
Add alpa_ex to your mix.exs:
def deps do
[{:alpa_ex, "~> 1.0"}]
endThen run:
mix deps.get
Configuration
Environment Variables (recommended)
export APCA_API_KEY_ID="your-key"
export APCA_API_SECRET_KEY="your-secret"
export APCA_USE_PAPER="true" # defaults to true for safety
Application Config
# config/runtime.exs
config :alpa_ex,
api_key: System.get_env("APCA_API_KEY_ID"),
api_secret: System.get_env("APCA_API_SECRET_KEY"),
use_paper: truePer-Call Override
Alpa.account(api_key: "other-key", api_secret: "other-secret")Quick Start
# Get account info
{:ok, account} = Alpa.account()
IO.puts("Buying power: $#{account.buying_power}")
# Check market status
{:ok, open?} = Alpa.market_open?()
# Place a market order
{:ok, order} = Alpa.buy("AAPL", 10)
# Get positions
{:ok, positions} = Alpa.positions()
# Get market data
{:ok, bars} = Alpa.bars("AAPL", timeframe: "1Day", limit: 30)
# Get a snapshot
{:ok, snapshot} = Alpa.snapshot("AAPL")Crypto Trading
# Buy crypto by quantity
{:ok, order} = Alpa.Crypto.Trading.buy("BTC/USD", "0.001")
# Buy crypto by dollar amount
{:ok, order} = Alpa.Crypto.Trading.buy_notional("BTC/USD", "100")
# Get crypto market data
{:ok, bars} = Alpa.Crypto.MarketData.bars("BTC/USD", timeframe: "1Hour")
{:ok, snapshots} = Alpa.Crypto.MarketData.snapshots(["BTC/USD", "ETH/USD"])Pagination
For endpoints that return paginated results:
# Fetch all orders across pages
{:ok, all_orders} = Alpa.Pagination.all(&Alpa.Trading.Orders.list/1, limit: 100)
# Or use lazy streaming
Alpa.Pagination.stream(&Alpa.Trading.Orders.list/1, limit: 50)
|> Stream.filter(fn order -> order.status == "filled" end)
|> Enum.to_list()Telemetry
Monitor API calls with telemetry:
:telemetry.attach("alpa-logger", [:alpa, :request, :stop], fn _event, measurements, metadata, _config ->
Logger.info("#{metadata.method} #{metadata.path} took #{div(measurements.duration, 1_000_000)}ms")
end, nil)Error Handling
All functions return {:ok, result} or {:error, %Alpa.Error{}}:
case Alpa.account() do
{:ok, account} -> IO.puts("Balance: $#{account.cash}")
{:error, %Alpa.Error{type: :unauthorized}} -> IO.puts("Check credentials")
{:error, %Alpa.Error{type: :rate_limited}} -> IO.puts("Rate limited")
{:error, error} -> IO.puts("Error: #{error}")
endWebSocket Streaming
# Stream trade updates
{:ok, pid} = Alpa.Stream.TradeUpdates.start_link(
callback: fn event -> IO.inspect(event, label: "trade_update") end
)
# Stream market data
{:ok, pid} = Alpa.Stream.MarketData.start_link(
feed: :iex,
trades: ["AAPL", "TSLA"],
callback: fn event -> IO.inspect(event) end
)Next Steps
- Architecture -- Understand the module structure and design
- API Coverage -- See all supported endpoints
- Trading Strategies -- Example trading patterns
- Contributing -- Help improve AlpaEx