Algorithmic Trading In Java with Alpaca
This is a Java implementation for the Alpaca API. Alpaca lets you trade with algorithms, connect with apps, and build services all with a commission-free stock trading API.
Please note that this article is for educational and informational purposes only. All screenshots are for illustrative purposes only. The views and opinions expressed are those of the author and do not reflect or represent the views and opinions of Alpaca. Alpaca does not recommend any specific securities or investment strategies
This article first appeared on GitHub pages, written by Jacob Peterson
Overview
This is a Java implementation for the Alpaca API. Alpaca lets you trade with algorithms, connect with apps, and build services all with a commission-free stock trading API. This library is community developed and if you have any questions, please ask them on Github Discussions, the Alpaca Slack #dev-alpaca-java channel, or on the Alpaca Forums.
Give this repository a star ⭐ if it helped you build a trading algorithm in Java!
Gradle and Maven Integration
If you are using Gradle as your build tool, add the following dependency to your build.gradle
file:
dependencies {
implementation group: 'net.jacobpeterson', name: 'alpaca-java', version: '8.3.1'
}
If you are using Maven as your build tool, add the following dependency to your pom.xml
file:
<dependency>
<groupId>net.jacobpeterson</groupId>
<artifactId>alpaca-java</artifactId>
<version>8.3.1</version>
<scope>compile</scope>
</dependency>
Note that you don’t have to use the Maven Central artifacts and instead can just install a clone of this project to your local Maven repository as shown in the Building section.
Configuration
Creating an alpaca.properties
file on the classpath with the following format allows you to easily load properties using the AlpacaAPI
default constructor:
key_id = <your Key ID>
secret_key = <your Secret Key>
endpoint_api_type = <must be either "paper" or "live">
data_api_type = <must be either "iex" or "sip">
The default values for alpaca.properties
can be found here.
Logger
For logging, this library uses SLF4j which serves as an interface for various logging frameworks. This enables you to use whatever logging framework you would like. However, if you do not add a logging framework as a dependency in your project, the console will output a message stating that SLF4j is defaulting to a no-operation (NOP) logger implementation. To enable logging, add a logging framework of your choice as a dependency to your project such as Logback, Log4j 2, SLF4j-simple, or Apache Commons Logging.
Examples
Note that the examples below are not exhaustive. Refer to the Javadoc for all classes and method signatures.
AlpacaAPI
The AlpacaAPI
class contains several instances of various AlpacaEndpoints
and AlpacaWebsockets
to interface with Alpaca. You will generally only need one instance of this class in your application. Note that many methods inside the various AlpacaEndpoints
allow null
to be passed in as a parameter if it is optional.
The Alpaca API specification is located here and the AlpacaAPI
Javadoc is located here.
Example usage:
// This constructor uses the 'alpaca.properties' file on the classpath for configuration
AlpacaAPI alpacaAPI = new AlpacaAPI();
// This constructor passes in a 'keyID' and 'secretKey' and uses the endpoint API type and data API
// type defined in the 'alpaca.properties' file (which default to 'paper' and 'iex' respectively)
String keyID = "<some key ID>";
String secretKey = "<some secret>";
AlpacaAPI alpacaAPI = new AlpacaAPI(keyID, secretKey);
// This constructor passes in a 'keyID' and 'secretKey' and uses the passed in endpoint API type
// and data API type (which are 'LIVE' and 'SIP' respectively in this example)
AlpacaAPI alpacaAPI = new AlpacaAPI(keyID, secretKey, EndpointAPIType.LIVE, DataAPIType.SIP);
// This constructor is for OAuth tokens
String oAuthToken = "<some OAuth token>";
AlpacaAPI alpacaAPI = new AlpacaAPI(oAuthToken);
Note that this library uses OkHttp as its HTTP client library which creates background threads to service requests. These threads persist even if the main thread exists so if you want to destroy these threads when you’re done using AlpacaAPI
so your program can exit without calling System.exit()
, use the following snippet:
alpacaAPI.getOkHttpClient().dispatcher().executorService().shutdown();
alpacaAPI.getOkHttpClient().connectionPool().evictAll();
See the OkHttpClient Documentation for more information.
AlpacaClientException
AlpacaClientException
is thrown anytime an exception occurs when using various AlpacaEndpoints
. It should be caught and handled within your trading algorithm application accordingly.
AccountEndpoint
The Account API serves important information related to an account, including account status, funds available for trade, funds available for withdrawal, and various flags relevant to an account’s ability to trade.
Example usage:
try {
// Get 'Account' information and print it out
Account account = alpacaAPI.account().get();
System.out.println(account);
} catch (AlpacaClientException exception) {
exception.printStackTrace();
}
MarketDataEndpoint
The Data API v2 provides market data through an easy-to-use API for historical data.
Example usage:
try {
// Get AAPL one hour, split-adjusted bars from 7/6/2021 market open
// to 7/8/2021 market close and print them out
BarsResponse aaplBarsResponse = alpacaAPI.marketData().getBars(
"AAPL",
ZonedDateTime.of(2021, 7, 6, 9, 30, 0, 0, ZoneId.of("America/New_York")),
ZonedDateTime.of(2021, 7, 8, 12 + 4, 0, 0, 0, ZoneId.of("America/New_York")),
null,
null,
1,
BarTimePeriod.HOUR,
BarAdjustment.SPLIT);
aaplBarsResponse.getBars().forEach(System.out::println);
// Get AAPL first 10 trades on 7/8/2021 at market open and print them out
TradesResponse aaplTradesResponse = alpacaAPI.marketData().getTrades(
"AAPL",
ZonedDateTime.of(2021, 7, 8, 9, 30, 0, 0, ZoneId.of("America/New_York")),
ZonedDateTime.of(2021, 7, 8, 9, 31, 0, 0, ZoneId.of("America/New_York")),
10,
null);
aaplTradesResponse.getTrades().forEach(System.out::println);
// Print out latest AAPL trade
Trade latestAAPLTrade = alpacaAPI.marketData().getLatestTrade("AAPL").getTrade();
System.out.printf("Latest AAPL Trade: %s\n", latestAAPLTrade);
// Print out snapshot of AAPL, GME, and TSLA
Map<String, Snapshot> snapshots = alpacaAPI.marketData()
.getSnapshots(Arrays.asList("AAPL", "GME", "TSLA"));
snapshots.forEach((symbol, snapshot) ->
System.out.printf("Symbol: %s\nSnapshot: %s\n\n", symbol, snapshot));
} catch (AlpacaClientException exception) {
exception.printStackTrace();
}
The Orders API allows a user to monitor, place, and cancel their orders with Alpaca.
Example usage:
try {
// Print all the 'Order's of AAPL and TSLA until 7/6/2021 in
// ascending (oldest to newest) order
List<Order> orders = alpacaAPI.orders().get(
CurrentOrderStatus.ALL,
null,
null,
ZonedDateTime.of(2021, 7, 6, 0, 0, 0, 0, ZoneId.of("America/New_York")),
SortDirection.ASCENDING,
true,
Arrays.asList("AAPL", "TSLA"));
orders.forEach(System.out::println);
// Request a new limit order for TSLA for 100 shares at a limit price
// of $653.00 and TIF of DAY.
Order tslaLimitOrder = alpacaAPI.orders().requestLimitOrder(
"TSLA",
100,
OrderSide.BUY,
OrderTimeInForce.DAY,
653.00,
false);
System.out.printf("Requested %s %s order at %s\n",
tslaLimitOrder.getSymbol(),
tslaLimitOrder.getType(),
tslaLimitOrder.getSubmittedAt());
// Check if TSLA limit order has filled 5 seconds later and if it hasn't
// replace it with a higher limit order so it fills!
Thread.sleep(5000);
tslaLimitOrder = alpacaAPI.orders().get(tslaLimitOrder.getId(), false);
if (tslaLimitOrder.getFilledAt() == null && tslaLimitOrder.getStatus().equals(OrderStatus.NEW)) {
Order replacedOrder = alpacaAPI.orders().replace(
tslaLimitOrder.getId(),
100,
OrderTimeInForce.DAY,
655.00,
null, null, null);
System.out.printf("Replaced TSLA order: %s\n", replacedOrder);
}
// Cancel all open orders after 2 seconds
Thread.sleep(2000);
List<CancelledOrder> cancelledOrders = alpacaAPI.orders().cancelAll();
cancelledOrders.forEach((cancelledOrder) -> System.out.printf("Cancelled: %s\n", cancelledOrder));
// Request a new fractional market order for 0.5 shares of GME
alpacaAPI.orders().requestFractionalMarketOrder("GME", 0.5, OrderSide.BUY);
// Request a new notional market order for $25 worth of GME shares
alpacaAPI.orders().requestNotionalMarketOrder("GME", 25d, OrderSide.BUY);
} catch (AlpacaClientException | InterruptedException exception) {
exception.printStackTrace();
}
The Positions API provides information about an account’s current open positions.
Example usage:
try {
// Close 50% of all open TSLA and AAPL positions
List<Position> openPositions = alpacaAPI.positions().get();
for (Position openPosition : openPositions) {
if (openPosition.getSymbol().equals("TSLA") || openPosition.getSymbol().equals("AAPL")) {
Order closePositionOrder = alpacaAPI.positions()
.close(openPosition.getSymbol(), null, 50d);
System.out.printf("Closing 50%% of %s position: %s\n",
openPosition.getSymbol(), closePositionOrder);
}
}
} catch (AlpacaClientException exception) {
exception.printStackTrace();
}
The Assets API serves as the master list of assets available for trade and data consumption from Alpaca.
Example usage:
try {
// Print out a CSV of all active US equity 'Asset's
List<Asset> activeUSEquities = alpacaAPI.assets().get(AssetStatus.ACTIVE, null);
System.out.println(activeUSEquities
.stream().map(Asset::getSymbol)
.collect(Collectors.joining(", ")));
// Print out TSLA 'Asset' information
Asset tslaAsset = alpacaAPI.assets().getBySymbol("TSLA");
System.out.println(tslaAsset);
} catch (AlpacaClientException exception) {
exception.printStackTrace();
}
The Watchlist API provides CRUD operation for the account’s watchlist.
Example usage:
try {
// Print out CSV all 'Watchlist' names
List<Watchlist> watchlists = alpacaAPI.watchlist().get();
System.out.println(watchlists.stream()
.map(Watchlist::getName)
.collect(Collectors.joining(", ")));
// Create a watchlist for day trading with TSLA and AAPL initially
Watchlist dayTradeWatchlist = alpacaAPI.watchlist().create("Day Trade", "TSLA", "AAPL");
// Remove TSLA and add MSFT to 'dayTradeWatchlist'
alpacaAPI.watchlist().removeSymbol(dayTradeWatchlist.getId(), "TSLA");
alpacaAPI.watchlist().addAsset(dayTradeWatchlist.getId(), "MSFT");
// Set the updated watchlist variable
dayTradeWatchlist = alpacaAPI.watchlist().get(dayTradeWatchlist.getId());
// Print CSV of 'dayTradeWatchlist' 'Asset's
System.out.println(dayTradeWatchlist.getAssets()
.stream().map(Asset::getSymbol)
.collect(Collectors.joining(", ")));
// Delete the 'dayTradeWatchlist'
alpacaAPI.watchlist().delete(dayTradeWatchlist.getId());
} catch (AlpacaClientException exception) {
exception.printStackTrace();
}
The calendar API serves the full list of market days from 1970 to 2029.
Example usage:
try {
// Get the 'Calendar's of the week of Christmas 2020 and print them out
List<Calendar> calendar = alpacaAPI.calendar().get(
LocalDate.of(2020, 12, 20),
LocalDate.of(2020, 12, 27));
calendar.forEach(System.out::println);
} catch (AlpacaClientException exception) {
exception.printStackTrace();
}
ClockEndpoint
The clock API serves the current market timestamp, whether the market is currently open, as well as the times of the next market open and close.
Example usage:
try {
// Get the market 'Clock' and print it out
Clock clock = alpacaAPI.clock().get();
System.out.println(clock);
} catch (AlpacaClientException exception) {
exception.printStackTrace();
}
AccountConfigurationEndpoint
The Account Configuration API provides custom configurations about your trading account settings. These configurations control various allow you to modify settings to suit your trading needs.
Example usage:
try {
// Update the 'AccountConfiguration' to block new orders
AccountConfiguration accountConfiguration = alpacaAPI.accountConfiguration().get();
accountConfiguration.setSuspendTrade(true);
alpacaAPI.accountConfiguration().set(accountConfiguration);
} catch (AlpacaClientException exception) {
exception.printStackTrace();
}
AccountActivitiesEndpoint
The Account Activities API provides access to a historical record of transaction activities that have impacted your account.
Example usage:
try {
// Print all order fill and cash deposit 'AccountActivity's on 7/8/2021
List<AccountActivity> accountActivities = alpacaAPI.accountActivities().get(
ZonedDateTime.of(2021, 7, 8, 0, 0, 0, 0, ZoneId.of("America/New_York")),
null,
null,
SortDirection.ASCENDING,
null,
null,
ActivityType.FILL, ActivityType.CSD);
for (AccountActivity accountActivity : accountActivities) {
if (accountActivity instanceof TradeActivity) {
System.out.println("TradeActivity: " + (TradeActivity) accountActivity);
} else if (accountActivity instanceof NonTradeActivity) {
System.out.println("NonTradeActivity: " + (NonTradeActivity) accountActivity);
}
}
} catch (AlpacaClientException exception) {
exception.printStackTrace();
}
PortfolioHistoryEndpoint
The Portfolio History API returns the timeseries data for equity and profit loss information of the account.
Example usage:
try {
// Get 3 days of one-hour 'PortfolioHistory' on 7/8/2021 and print out its data points
PortfolioHistory portfolioHistory = alpacaAPI.portfolioHistory().get(
3,
PortfolioPeriodUnit.DAY,
PortfolioTimeFrame.ONE_HOUR,
LocalDate.of(2021, 7, 8),
false);
System.out.printf("Timeframe: %s, Base value: %s \n",
portfolioHistory.getTimeframe(),
portfolioHistory.getBaseValue());
portfolioHistory.getDataPoints().forEach(System.out::println);
} catch (AlpacaClientException exception) {
exception.printStackTrace();
}
StreamingWebsocket
Alpaca offers WebSocket streaming of order updates.
Example usage:
// Add a 'StreamingListener' that simply prints streaming information
StreamingListener streamingListener = (messageType, message) ->
System.out.printf("%s: %s\n", messageType.name(), message);
alpacaAPI.streaming().setListener(streamingListener);
// Listen 'AuthorizationMessage' and 'ListeningMessage' messages that contain
// information about the stream's current state. Note that these are subscribed
// to before the websocket is connected since these messages usually are sent
// upon websocket connection.
alpacaAPI.streaming().streams(StreamingMessageType.AUTHORIZATION,
StreamingMessageType.LISTENING);
// Connect the websocket and confirm authentication
alpacaAPI.streaming().connect();
alpacaAPI.streaming().waitForAuthorization(5, TimeUnit.SECONDS);
if (!alpacaAPI.streaming().isValid()) {
System.out.println("Websocket not valid!");
return;
}
// Listen to the 'trade update' streams.
alpacaAPI.streaming().streams(StreamingMessageType.TRADE_UPDATES);
// Wait a few seconds
Thread.sleep(5000);
// Manually disconnect the websocket
alpacaAPI.streaming().disconnect();
Alpaca’s Data API v2 provides websocket streaming for trades, quotes, and minute bars. This helps receive the most up-to-date market information that could help your trading strategy to act upon certain market movement.
Example usage:
// Add a 'MarketDataListener' that simply prints market data information
MarketDataListener marketDataListener = (messageType, message) ->
System.out.printf("%s: %s\n", messageType.name(), message);
alpacaAPI.marketDataStreaming().setListener(marketDataListener);
// Listen to 'SubscriptionsMessage', 'SuccessMessage', and 'ErrorMessage' control messages
// that contain information about the stream's current state. Note that these are subscribed
// to before the websocket is connected since these messages usually are sent
// upon websocket connection.
alpacaAPI.marketDataStreaming().subscribeToControl(
MarketDataMessageType.SUCCESS,
MarketDataMessageType.SUBSCRIPTION,
MarketDataMessageType.ERROR);
// Connect the websocket and confirm authentication
alpacaAPI.marketDataStreaming().connect();
alpacaAPI.marketDataStreaming().waitForAuthorization(5, TimeUnit.SECONDS);
if (!alpacaAPI.marketDataStreaming().isValid()) {
System.out.println("Websocket not valid!");
return;
}
// Listen to the AAPL and TSLA trades and all ('*') bars.
alpacaAPI.marketDataStreaming().subscribe(
Arrays.asList("AAPL", "TSLA"),
null,
Arrays.asList("*"));
// Wait a few seconds
Thread.sleep(5000);
// Manually disconnect the websocket
alpacaAPI.marketDataStreaming().disconnect();
Building
To build this project yourself, clone this repository and run:
./gradlew build
To install built artifacts to your local maven repo, run:
./gradlew install -x test
Testing
To run mocked tests using Mockito, run:
./gradlew test
Note that mocked tests never send real API requests to Alpaca. Mocked tests are meant to test the basic integrity of this API locally.
To run live endpoint tests with Alpaca Paper credentials, create the alpaca.properties
file in src/test/resources
with the corresponding credentials. Then run:
./gradlew test -PtestPackage=live
Note that the live tests will modify your account minimally. It’s meant to test live endpoints on a real paper account during market hours to confirm that API methods are working properly. Please read through the live endpoint tests here before running this testing suite on your own paper account.
To-Do
- Finish Unit Testing (both live and mocked)
- Use TA4j
Num
interface instead ofDouble
for number variables so that users can use eitherDouble
orBigDecimal
for performance or precision in price data. - Add TimeSeriesDataStore using Alpaca Data API
Contributing
Contributions are welcome!
If you are creating a Pull Request, be sure to create a new branch in your forked repository for your feature or bug fix instead of committing directly to the master
branch in your fork.
Alpaca does not prepare, edit, or endorse Third Party Content. Alpaca does not guarantee the accuracy, timeliness, completeness or usefulness of Third Party Content, and is not responsible or liable for any content, advertising, products, or other materials on or available from third party sites.
Brokerage services are provided by Alpaca Securities LLC ("Alpaca"), member FINRA/SIPC, a wholly-owned subsidiary of AlpacaDB, Inc. Technology and services are offered by AlpacaDB, Inc. This is not an offer, solicitation of an offer, or advice to buy or sell securities, or open a brokerage account in any jurisdiction where Alpaca is not registered (Alpaca is registered only in the United States).