Current section
4 Versions
Jump to
Current section
4 Versions
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…