Packages

Elixir client library for the Alpaca Trading API. Supports trading, market data, and account management.

Current section

4 Versions

Jump to

Compare versions

45 files changed
+1203 additions
-570 deletions
  @@ -5,11 +5,35 @@ All notable changes to this project will be documented in this file.
5 5 The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6 6 and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7 7
8 + ## [1.0.1] - 2026-01-31
9 +
10 + ### Added
11 +
12 + - Facade delegates for `Alpa.Options.Contracts` (`option_contracts/1`, `option_contract/2`, `option_search/2`)
13 + - Facade delegates for `Alpa.Crypto.Trading` (`crypto_buy/3`, `crypto_sell/3`, `crypto_place_order/1`, `crypto_assets/1`, `crypto_positions/1`)
14 + - CI pipeline with formatting, credo --strict, and dialyzer checks
15 + - `.dialyzer_ignore.exs` for ExVCR/CaseTemplate compatibility
16 +
17 + ### Fixed
18 +
19 + - Reduced cyclomatic complexity in `Client.request` and `Pagination.do_fetch_all`
20 + - Use implicit `try` in WebSocket modules (credo --strict compliance)
21 + - Alphabetized alias groups in crypto modules
22 + - Code formatting across all source files
23 + - Elixir version requirement lowered to `~> 1.14` (was `~> 1.16`)
24 + - LICENSE link in README uses absolute URL for HexDocs compatibility
25 + - `.gitignore` pattern for hex build tarballs (`*.tar`)
26 + - Documentation consistency across README, hex docs, and wiki
27 +
28 + ### Changed
29 +
30 + - Minimum Elixir version: 1.14 (was 1.16)
31 +
8 32 ## [1.0.0] - 2026-01-10
9 33
10 34 ### Added
11 35
12 - - Complete rewrite with modern Elixir 1.16+ stack
36 + - Complete rewrite with modern Elixir 1.14+ stack
13 37 - **HTTP Client**: Switched from HTTPoison to Req for better performance and DX
14 38 - **TypedStruct Models**: All API responses now use typed structs with Decimal precision
15 39 - **Runtime Configuration**: Proper runtime config via `config/runtime.exs`
  @@ -54,7 +78,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
54 78
55 79 ### Changed
56 80
57 - - Minimum Elixir version: 1.16 (was 1.10)
81 + - Minimum Elixir version: 1.14 (was 1.10)
58 82 - API responses now return typed structs instead of raw maps
59 83 - Configuration uses runtime.exs instead of compile-time config
60 84 - Error handling uses structured `Alpa.Error` type
  @@ -24,7 +24,7 @@ Commission-free stock, options, and crypto trading with real-time market data.
24 24 - **Corporate Actions** - Announcements and corporate action tracking
25 25 - **Pagination Helpers** - Eager `all/2` and lazy `stream/2` for paginated endpoints
26 26 - **Telemetry** - Built-in `:telemetry` events for observability
27 - - **Modern Stack** - Elixir 1.16+, Req HTTP client, WebSockex
27 + - **Modern Stack** - Elixir 1.14+, Req HTTP client, WebSockex
28 28
29 29 ## Installation
30 30
  @@ -310,6 +310,8 @@ Alpa.Stream.MarketData.stop(pid)
310 310 | `Alpa.Crypto.Trading` | Crypto trading operations |
311 311 | `Alpa.Crypto.MarketData` | Crypto bars, quotes, trades, snapshots, order books |
312 312 | `Alpa.Crypto.Funding` | Crypto transfers and wallets |
313 + | `Alpa.Helpers` | Shared parse helpers (decimal, datetime, date) |
314 + | `Alpa.Resource` | Macro for generating typed CRUD modules |
313 315
314 316 ## Error Handling
315 317
  @@ -335,13 +337,13 @@ Error types: `:unauthorized`, `:forbidden`, `:not_found`, `:unprocessable_entity
335 337
336 338 ## Configuration Options
337 339
338 - | Option | Environment Variable | Default |
339 - |--------|---------------------|---------|
340 - | `api_key` | `APCA_API_KEY_ID` | - |
341 - | `api_secret` | `APCA_API_SECRET_KEY` | - |
342 - | `use_paper` | `APCA_USE_PAPER` | `true` |
343 - | `timeout` | - | `30_000` |
344 - | `receive_timeout` | - | `30_000` |
340 + | Option | Environment Variable | Fallback | Default |
341 + |--------|---------------------|----------|---------|
342 + | `api_key` | `APCA_API_KEY_ID` | `ALPACA_API_KEY` | - |
343 + | `api_secret` | `APCA_API_SECRET_KEY` | `ALPACA_API_SECRET` | - |
344 + | `use_paper` | `APCA_USE_PAPER` | - | `true` |
345 + | `timeout` | - | - | `30_000` |
346 + | `receive_timeout` | - | - | `30_000` |
345 347
346 348 Options can be passed to any function to override config:
347 349
  @@ -372,5 +374,6 @@ MIT License - see [LICENSE](https://github.com/phiat/alpa_ex/blob/main/LICENSE)
372 374
373 375 ## Links
374 376
377 + - [Hex Docs](https://hexdocs.pm/alpa_ex)
375 378 - [Alpaca API Documentation](https://docs.alpaca.markets/)
376 - - [GitHub Repository](https://github.com/phiat/alpa_ex)
379 + - [Previous version (alpa)](https://github.com/phiat/alpa)
unknownassets/alpa_ex.png
File is too large to be displayed (1 MiB limit).
  @@ -2,14 +2,14 @@
2 2 [{<<"Alpaca API Docs">>,<<"https://docs.alpaca.markets">>},
3 3 {<<"GitHub">>,<<"https://github.com/phiat/alpa_ex">>}]}.
4 4 {<<"name">>,<<"alpa_ex">>}.
5 - {<<"version">>,<<"1.0.0">>}.
5 + {<<"version">>,<<"1.0.1">>}.
6 6 {<<"description">>,
7 7 <<"Elixir client library for the Alpaca Trading API.\nSupports trading, market data, and account management.">>}.
8 - {<<"elixir">>,<<"~> 1.16">>}.
8 + {<<"elixir">>,<<"~> 1.14">>}.
9 9 {<<"app">>,<<"alpa_ex">>}.
10 10 {<<"licenses">>,[<<"MIT">>]}.
11 11 {<<"files">>,
12 - [<<"lib">>,<<"lib/alpa">>,<<"lib/alpa/crypto">>,
12 + [<<"lib">>,<<"lib/alpa">>,<<"lib/alpa/helpers.ex">>,<<"lib/alpa/crypto">>,
13 13 <<"lib/alpa/crypto/market_data.ex">>,<<"lib/alpa/crypto/trading.ex">>,
14 14 <<"lib/alpa/crypto/funding.ex">>,<<"lib/alpa/client.ex">>,
15 15 <<"lib/alpa/market_data">>,<<"lib/alpa/market_data/bars.ex">>,
  @@ -28,9 +28,10 @@
28 28 <<"lib/alpa/models/account_config.ex">>,<<"lib/alpa/models/snapshot.ex">>,
29 29 <<"lib/alpa/models/watchlist.ex">>,<<"lib/alpa/models/option_contract.ex">>,
30 30 <<"lib/alpa/models/corporate_action.ex">>,<<"lib/alpa/models/bar.ex">>,
31 - <<"lib/alpa/trading">>,<<"lib/alpa/trading/orders.ex">>,
32 - <<"lib/alpa/trading/positions.ex">>,<<"lib/alpa/trading/account.ex">>,
33 - <<"lib/alpa/trading/market.ex">>,<<"lib/alpa/trading/watchlists.ex">>,
31 + <<"lib/alpa/resource.ex">>,<<"lib/alpa/trading">>,
32 + <<"lib/alpa/trading/orders.ex">>,<<"lib/alpa/trading/positions.ex">>,
33 + <<"lib/alpa/trading/account.ex">>,<<"lib/alpa/trading/market.ex">>,
34 + <<"lib/alpa/trading/watchlists.ex">>,
34 35 <<"lib/alpa/trading/corporate_actions.ex">>,
35 36 <<"lib/alpa/trading/assets.ex">>,<<"lib/alpa/error.ex">>,
36 37 <<"lib/alpa/options">>,<<"lib/alpa/options/contracts.ex">>,
  @@ -31,20 +31,23 @@ defmodule Alpa do
31 31
32 32 For more advanced usage, use the specific modules:
33 33
34 - * `Alpa.Trading.Account` - Account information and configuration
34 + * `Alpa.Trading.Account` - Account info, config, activities, portfolio history
35 35 * `Alpa.Trading.Orders` - Order placement and management
36 36 * `Alpa.Trading.Positions` - Position management
37 37 * `Alpa.Trading.Assets` - Asset information
38 - * `Alpa.Trading.Watchlists` - Watchlist management
38 + * `Alpa.Trading.Watchlists` - Watchlist CRUD
39 39 * `Alpa.Trading.Market` - Market clock and calendar
40 + * `Alpa.Trading.CorporateActions` - Corporate action announcements
40 41 * `Alpa.MarketData.Bars` - Historical bar data
41 - * `Alpa.MarketData.Quotes` - Quote (NBBO) data
42 - * `Alpa.MarketData.Trades` - Trade data
42 + * `Alpa.MarketData.Quotes` - Historical quote data
43 + * `Alpa.MarketData.Trades` - Historical trade data
43 44 * `Alpa.MarketData.Snapshots` - Market snapshots
44 - * `Alpa.Crypto.Trading` - Crypto trading (orders, positions, assets)
45 - * `Alpa.Crypto.MarketData` - Crypto market data (bars, quotes, trades, snapshots)
46 - * `Alpa.Crypto.Funding` - Crypto wallets and transfers
47 - * `Alpa.Options.Contracts` - Options contract search and lookup
45 + * `Alpa.Stream.TradeUpdates` - Real-time trade updates
46 + * `Alpa.Stream.MarketData` - Real-time market data
47 + * `Alpa.Options.Contracts` - Options contract search
48 + * `Alpa.Crypto.Trading` - Crypto trading operations
49 + * `Alpa.Crypto.MarketData` - Crypto bars, quotes, trades, snapshots, order books
50 + * `Alpa.Crypto.Funding` - Crypto transfers and wallets
48 51
49 52 ## Configuration
50 53
  @@ -61,7 +64,7 @@ defmodule Alpa do
61 64 alias Alpa.Crypto.MarketData, as: CryptoMarketData
62 65 alias Alpa.Crypto.Trading, as: CryptoTrading
63 66 alias Alpa.MarketData.{Bars, Quotes, Snapshots, Trades}
64 - alias Alpa.Options.Contracts
67 + alias Alpa.Options.Contracts, as: OptionsContracts
65 68 alias Alpa.Trading.{Account, Assets, CorporateActions, Market, Orders, Positions, Watchlists}
66 69
67 70 # ============================================================================
  @@ -447,14 +450,14 @@ defmodule Alpa do
447 450
448 451 See `Alpa.Crypto.Trading.buy/3` for details.
449 452 """
450 - defdelegate crypto_buy(symbol, qty, opts \\ []), to: CryptoTrading, as: :buy
453 + def crypto_buy(symbol, qty, opts \\ []), do: CryptoTrading.buy(symbol, qty, opts)
451 454
452 455 @doc """
453 456 Sell crypto with a market order.
454 457
455 458 See `Alpa.Crypto.Trading.sell/3` for details.
456 459 """
457 - defdelegate crypto_sell(symbol, qty, opts \\ []), to: CryptoTrading, as: :sell
460 + def crypto_sell(symbol, qty, opts \\ []), do: CryptoTrading.sell(symbol, qty, opts)
458 461
459 462 @doc """
460 463 Get all crypto positions.
  @@ -464,7 +467,7 @@ defmodule Alpa do
464 467 defdelegate crypto_positions(opts \\ []), to: CryptoTrading, as: :positions
465 468
466 469 # ============================================================================
467 - # Options
470 + # Options Contracts
468 471 # ============================================================================
469 472
470 473 @doc """
  @@ -472,19 +475,110 @@ defmodule Alpa do
472 475
473 476 See `Alpa.Options.Contracts.list/1` for details.
474 477 """
475 - defdelegate option_contracts(opts \\ []), to: Contracts, as: :list
478 + def option_contracts(opts \\ []), do: OptionsContracts.list(opts)
476 479
477 480 @doc """
478 481 Get a specific option contract by symbol or ID.
479 482
480 483 See `Alpa.Options.Contracts.get/2` for details.
481 484 """
482 - defdelegate option_contract(symbol_or_id, opts \\ []), to: Contracts, as: :get
485 + def option_contract(symbol_or_id, opts \\ []), do: OptionsContracts.get(symbol_or_id, opts)
483 486
484 487 @doc """
485 488 Search for option contracts by underlying symbol.
486 489
487 490 See `Alpa.Options.Contracts.search/2` for details.
488 491 """
489 - defdelegate option_search(underlying_symbol, opts \\ []), to: Contracts, as: :search
492 + defdelegate option_search(underlying_symbol, opts \\ []), to: OptionsContracts, as: :search
493 +
494 + # ============================================================================
495 + # Account (additional)
496 + # ============================================================================
497 +
498 + @doc """
499 + Update account configurations.
500 +
501 + See `Alpa.Trading.Account.update_configurations/1` for details.
502 + """
503 + defdelegate update_configurations(settings), to: Account, as: :update_configurations
504 +
505 + @doc """
506 + Get account activities.
507 +
508 + See `Alpa.Trading.Account.get_activities/1` for details.
509 + """
510 + def get_activities(opts \\ []), do: Account.get_activities(opts)
511 +
512 + @doc """
513 + Get account activities for a specific activity type.
514 +
515 + See `Alpa.Trading.Account.get_activities_by_type/2` for details.
516 + """
517 + def get_activities_by_type(activity_type, opts \\ []),
518 + do: Account.get_activities_by_type(activity_type, opts)
519 +
520 + # ============================================================================
521 + # Orders (additional)
522 + # ============================================================================
523 +
524 + @doc """
525 + Get an order by client order ID.
526 +
527 + See `Alpa.Trading.Orders.get_by_client_id/2` for details.
528 + """
529 + def get_order_by_client_id(client_order_id, opts \\ []),
530 + do: Orders.get_by_client_id(client_order_id, opts)
531 +
532 + @doc """
533 + Replace (modify) an existing order.
534 +
535 + See `Alpa.Trading.Orders.replace/2` for details.
536 + """
537 + defdelegate replace_order(order_id, params), to: Orders, as: :replace
538 +
539 + # ============================================================================
540 + # Multi-symbol Market Data
541 + # ============================================================================
542 +
543 + @doc """
544 + Get historical bars for multiple symbols.
545 +
546 + See `Alpa.MarketData.Bars.get_multi/2` for details.
547 + """
548 + def bars_multi(symbols, opts \\ []), do: Bars.get_multi(symbols, opts)
549 +
550 + @doc """
551 + Get historical quotes for multiple symbols.
552 +
553 + See `Alpa.MarketData.Quotes.get_multi/2` for details.
554 + """
555 + def quotes_multi(symbols, opts \\ []), do: Quotes.get_multi(symbols, opts)
556 +
557 + @doc """
558 + Get historical trades for multiple symbols.
559 +
560 + See `Alpa.MarketData.Trades.get_multi/2` for details.
561 + """
562 + def trades_multi(symbols, opts \\ []), do: Trades.get_multi(symbols, opts)
563 +
564 + @doc """
565 + Get latest bars for multiple symbols.
566 +
567 + See `Alpa.MarketData.Bars.latest_multi/2` for details.
568 + """
569 + def latest_bars_multi(symbols, opts \\ []), do: Bars.latest_multi(symbols, opts)
570 +
571 + @doc """
572 + Get latest quotes for multiple symbols.
573 +
574 + See `Alpa.MarketData.Quotes.latest_multi/2` for details.
575 + """
576 + def latest_quotes_multi(symbols, opts \\ []), do: Quotes.latest_multi(symbols, opts)
577 +
578 + @doc """
579 + Get latest trades for multiple symbols.
580 +
581 + See `Alpa.MarketData.Trades.latest_multi/2` for details.
582 + """
583 + def latest_trades_multi(symbols, opts \\ []), do: Trades.latest_multi(symbols, opts)
490 584 end
Loading more files…