Skip to content

117/alpaca

main
Switch branches/tags
Code

alpaca

version code build prettier

A TypeScript Node.js library for the https://alpaca.markets REST API and WebSocket streams.

Contents

Features

  • Fully typed.
  • Fully asynchronous promise based API.
  • Extensible AlpacaClient and AlpacaStream classes.
  • Built-in rate limiting.
  • Built-in number and date parsing.
  • A 1:1 mapping of the official Alpaca docs.
  • Auto-transpiled modern ESM alternative.
  • OAuth integration support.
  • Minified and non-minified bundles.
  • Various bundles provided:
    • alpaca.js - ESM bundle (for node)
    • alpaca.bundle.js - ESM bundle with dependencies (for node)
    • alpaca.browser.js - UMD bundle (for browser)
    • alpaca.browser.modern.js - ESM modern bundle (for browser)

Install

From NPM:

> npm i @master-chief/alpaca

From GitHub:

From these popular CDNs:

Import

Import with CommonJS:

let { AlpacaClient, AlpacaStream } = require('@master-chief/alpaca');

Import with ESM:

import { AlpacaClient, AlpacaStream } from '@master-chief/alpaca';

Import as script:

<script src="https://unpkg.com/@master-chief/alpaca/dist/alpaca.browser.min.js"></script>

Import as module:

<script type="module">
  import alpaca from 'alpaca.browser.modern.min.js';
</script>

Client

Creating a new client

If you wish to use env vars, populate these fields with process.env on your own. Paper account key detection is automatic. Using OAuth? Simply pass an access_token in the credentials object.

const client = new AlpacaClient({
  credentials: {
    key: 'xxxxxx',
    secret: 'xxxxxxxxxxxx',
    // access_token: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
    paper: true,
  },
  rate_limit: true,
});

Built-in parsing

Alpaca provides numbers as strings. From their docs:

Decimal numbers are returned as strings to preserve full precision across platforms. When making a request, it is recommended that you also convert your numbers to strings to avoid truncation and precision errors.

This package provides numbers as number instead, and date strings as Date objects which is what most developers want out of the box. If you want the original data, as it came from Alpaca, you can call raw() on any entity.

const account = await client.getAccount();

console.log(typeof account.buying_power); // number
console.log(typeof account.raw().buying_power); // string

Methods

The following methods are available on the client.

Account

Market Data v1

Market Data v2

isAuthenticated

await client.isAuthenticated();

getAccount

await client.getAccount();

getOrder

await client.getOrder({ order_id: '6187635d-04e5-485b-8a94-7ce398b2b81c' });

getOrders

await client.getOrders({ limit: 25, status: 'all' });

placeOrder

await client.placeOrder({
  symbol: 'SPY',
  qty: 1,
  // or
  // notional: 100,
  side: 'buy',
  type: 'market',
  time_in_force: 'day',
});

replaceOrder

await client.replaceOrder({
  order_id: '69a3db8b-cc63-44da-a26a-e3cca9490308',
  limit_price: 9.74,
});

cancelOrder

await client.cancelOrder({ order_id: '69a3db8b-cc63-44da-a26a-e3cca9490308' });

cancelOrders

await client.cancelOrders();

getPosition

await client.getPosition({ symbol: 'SPY' });

getPositions

await client.getPositions();

closePosition

await client.closePosition({ symbol: 'SPY' });

closePositions

await client.closePositions();

getAsset

await client.getAsset({ asset_id_or_symbol: 'SPY' });

getAssets

await client.getAssets({ status: 'active' });

getWatchlist

await client.getWatchlist({ uuid: '2000e463-6f87-41c0-a8ba-3e40cbf67128' });

getWatchlists

await client.getWatchlists();

createWatchlist

await client.createWatchlist({
  name: 'my watchlist',
  symbols: ['SPY', 'DIA', 'EEM', 'XLF'],
});

updateWatchlist

await client.updateWatchlist({
  uuid: '2000e463-6f87-41c0-a8ba-3e40cbf67128',
  name: 'new watchlist name',
  symbols: ['TSLA', 'AAPL'],
});

addToWatchlist

await client.addToWatchlist({
  uuid: '2000e463-6f87-41c0-a8ba-3e40cbf67128',
  symbol: 'F',
});

removeFromWatchlist

await client.removeFromWatchlist({
  uuid: '2000e463-6f87-41c0-a8ba-3e40cbf67128',
  symbol: 'F',
});

deleteWatchlist

await client.deleteWatchlist({ uuid: '2000e463-6f87-41c0-a8ba-3e40cbf67128' });

getCalendar

await client.getCalendar({ start: new Date(), end: new Date() });

getClock

await client.getClock();

getAccountConfigurations

await client.getAccountConfigurations();

updateAccountConfigurations

await client.updateAccountConfigurations({
  no_shorting: true,
  suspend_trade: true,
});

getAccountActivities

await client.getAccountActivities({ activity_type: 'FILL' });

getPortfolioHistory

await client.getPortfolioHistory({ period: '1D', timeframe: '1Min' });

getLastTrade_v1

await client.getLastTrade_v1({ symbol: 'SPY' });

getLastQuote_v1

await client.getLastQuote_v1({ symbol: 'SPY' });

getBars_v1

await client.getBars_v1({ symbols: ['SPY', 'DIA', 'XLF'], timeframe: '1Min' });

getLatestTrade

await client.getLatestTrade({ symbol: 'SPY' });

getTrades

Basic
await client.getTrades({
  symbol: 'SPY',
  start: new Date('2021-02-26T14:30:00.007Z'),
  end: new Date('2021-02-26T14:35:00.007Z'),
});
Paginated
let trades = []
let page_token = ''

// until the next token we receive is null
while (page_token != null) {
  let resp = await client.getTrades({ ..., page_token })
  trades.push(...resp.trades)
  page_token = resp.next_page_token
}

// wooh! we have collected trades from multiple pages
console.log(trades.length)

getQuotes

Basic
await client.getQuotes({
  symbol: 'SPY',
  start: new Date('2021-02-26T14:30:00.007Z'),
  end: new Date('2021-02-26T14:35:00.007Z'),
});
Paginated
let quotes = []
let page_token = ''

// until the next token we receive is null
while (page_token != null) {
  let resp = await client.getQuotes({ ..., page_token })
  quotes.push(...resp.quotes)
  page_token = resp.next_page_token
}

// wooh! we have collected quotes from multiple pages
console.log(quotes.length)

getBars

Basic
await client.getBars({
  symbol: 'SPY',
  start: new Date('2021-02-26T14:30:00.007Z'),
  end: new Date('2021-02-26T14:35:00.007Z'),
  timeframe: '1Min',
  // page_token: "MjAyMS0wMi0wNlQxMzowOTo0Mlo7MQ=="
});
Paginated
let bars = []
let page_token = ''

// until the next token we receive is null
while (page_token != null) {
  let resp = await client.getBars({ ..., page_token })
  bars.push(...resp.bars)
  page_token = resp.next_page_token
}

// wooh! we have collected bars from multiple pages
console.log(bars.length)

getSnapshot

await client.getSnapshot({ symbol: 'SPY' });

getSnapshots

await client.getSnapshots({ symbols: ['SPY', 'DIA'] });

getNews

await client.getNews({ symbols: ['SPY'] });

Stream

Creating a new stream

If you wish to use env vars, populate these fields with process.env on your own.

import { AlpacaStream } from '@master-chief/alpaca';

const stream = new AlpacaStream({
  credentials: {
    key: 'xxxxxx',
    secret: 'xxxxxxxxxxxx',
    paper: true,
  },
  type: 'market_data', // or "account"
  source: 'iex', // or "sip" depending on your subscription
});

Methods

The following methods are available on the stream.

Channels

Channel Type
trade_updates account
trades market_data
quotes market_data
bars market_data

subscribe

stream.once('authenticated', () =>
  stream.subscribe('bars', ['SPY', 'AAPL', 'TSLA']),
);

unsubscribe

stream.unsubscribe('bars', ['SPY']);

on

stream.on('message', (message) => console.log(message));
stream.on('trade', (trade) => console.log(trade));
stream.on('bar', (bar) => console.log(bar));
stream.on('quote', (quote) => console.log(quote));
stream.on('trade_updates', (update) => console.log(update));
stream.on('error', (error) => console.warn(error));

getConnection

stream.getConnection();

Common Issues

If you are having difficulty getting Jest to work with this library, add this to your configuration:

moduleNameMapper: {
  '@master-chief/alpaca': '<rootDir>/node_modules/@master-chief/alpaca/dist/cjs/index.cjs',
},

Credit to @calvintwr and @wailinkyaww for finding this solution.

Examples

Don't know where to start? Check out our community-made examples here.

Contributing

Feel free to contribute and PR to your 💖's content.