Skip to content

fix(@typedtrader/exchange): report real crypto fees on Alpaca fills#1177

Open
bennycode wants to merge 2 commits into
mainfrom
fix/alpaca-crypto-fill-fees
Open

fix(@typedtrader/exchange): report real crypto fees on Alpaca fills#1177
bennycode wants to merge 2 commits into
mainfrom
fix/alpaca-crypto-fill-fees

Conversation

@bennycode

Copy link
Copy Markdown
Owner

Summary

  • AlpacaBrokerMapper.toFilledOrder hardcoded fee: '0' on every fill, so realized P&L for crypto silently ignored Alpaca's crypto commission. Alpaca's order payload carries no fee field, so the mapper now derives it from the broker's fee rates for asset_class: 'crypto' orders.
  • Fee follows Alpaca's credited-asset rule (https://docs.alpaca.markets/docs/crypto-fees): a BUY pays in the credited base asset (filled_qty x rate), a SELL pays in the credited counter/fiat (filled_qty x filled_avg_price x rate). Limit orders bill at the maker rate (0.0015); all other order types execute as takers (0.0025). All money math uses big.js; wire types stay string-based and the Fill shape is unchanged.
  • Stocks/ETFs remain fee '0' (commission-free).
  • toFilledOrder now takes the FeeRate as a parameter: getFills passes await this.getFeeRates(pair); the account-wide trading stream uses AlpacaBroker.DEFAULT_FEE_RATES (same values today) since there is no single pair to query.
  • A filled order without filled_avg_price now throws instead of mapping price: 'null'.
  • position: OrderPosition.LONG stays: Alpaca's order payload exposes no position side (a SELL closing a long is indistinguishable from one opening a short), and this integration only trades long — now documented at the assignment.

Test plan

  • npm test in packages/exchange (87 tests, 8 files) — includes new mapper cases: stock fill maps with fee '0'; crypto MARKET BUY charges 2.5 BTC x 0.0025 = '0.00625' in BTC; crypto LIMIT SELL charges 0.4 x 61234.5 x 0.0015 = '36.7407' in USD (exact Big string assertions)
  • npm run lint in packages/exchange
  • npx lerna run dist --scope trading-strategies --include-dependencies (3 projects build cleanly)

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the Alpaca exchange integration to stop hardcoding zero fees on fills and instead compute Alpaca crypto commissions (keeping stocks/ETFs commission-free), while also making toFilledOrder reject filled orders that lack an average fill price.

Changes:

  • Compute realized crypto fees in AlpacaBrokerMapper.toFilledOrder using big.js, and plumb fee rates into the mapper.
  • Update Alpaca broker call sites to pass fee rates (pair-specific for REST getFills, default schedule for account-wide streaming).
  • Expand mapper unit tests to cover crypto fee calculation cases and the new mapper signature.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
packages/exchange/src/broker/alpaca/AlpacaBrokerMapper.ts Derives crypto fill fees and throws when filled_avg_price is missing; updates fill mapping accordingly.
packages/exchange/src/broker/alpaca/AlpacaBrokerMapper.test.ts Adds coverage for crypto maker/taker fee computations and updates tests for new mapper signature.
packages/exchange/src/broker/alpaca/AlpacaBroker.ts Passes fee rates into fill mapping for both REST fill fetching and the trading stream.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +129 to +131
if (order.asset_class === 'crypto') {
const feeRate = order.type === 'limit' ? feeRates.LIMIT : feeRates.MARKET;
const filledQty = new Big(order.filled_qty);
* The stream is account-wide (no single pair to query rates for), so the default fee
* schedule is used — the same values `getFeeRates` returns today.
*/
const fill = AlpacaBrokerMapper.toFilledOrder(message.order, pair, AlpacaBroker.DEFAULT_FEE_RATES);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants