You've successfully subscribed to Alpaca Learn | Developer-First API for Crypto and Stocks
Great! Next, complete checkout for full access to Alpaca Learn | Developer-First API for Crypto and Stocks
Welcome back! You've successfully signed in.
Success! Your account is fully activated, you now have access to all content.
Success! Your billing info is updated.
Billing info update failed.
Crypto

Make Your Own Crypto ETF Analog using Alpaca’s Crypto API

Rahul Chowdhury
Rahul Chowdhury

Since the release of cryptocurrency trading on Alpaca Crypto, we’ve continuously enhanced our offering. Cryptocurrency trading is now available in all U.S. states except New York. We also support trading of over 20 coins including Solana, Uniswap and even Dogecoin!

If you’re a crypto investor or trader, this may help you to diversify your crypto holdings and tackle new markets. If you’re a fintech app developer, cryptocurrencies are available for your users through OAuth.

In this post, learn how to take advantage of our new coin offerings by creating a diverse basket of crypto holdings. In the following sections we systematically allocate our portfolio to a basket of coins, which will comprise our functional equivalent of an “ETF".* We then regularly rebalance our "ETF" analog to help keep our allocation balanced across each coin.

Getting Started

To start crypto trading on Alpaca, sign up for an Alpaca account and retrieve your API keys.

We’ll use the python programming language in this article with the alpaca-trade-api SDK, which makes it easy to get started with retrieving data and placing orders. We can use pip to install the alpaca-trade-api SDK. To do so, run the following command in your terminal.

pip install alpaca-trade-api

Then we can import the SDK and instantiate a client with our API keys. We’ve made sure to also pass in the URL for the paper api. This way our orders will be placed in a sandbox environment instead of the live environment with real cash. Now we’re set to start retrieving crypto data and start placing trades.

from alpaca_trade_api.rest import REST, TimeFrame

API_KEY = "Your API Key"
SECRET_KEY = "Your Secret Key"

alpaca_client = REST(API_KEY, SECRET_KEY, ‘http://paper-api.alpaca.markets’)

Comparing Historical Crypto Returns

One way to help limit risk when investing in crypto is to evenly expose ourselves across many coins. This lets us tie our portfolio to the cryptocurrency sector as a whole, rather than one specific coin, and helps mitigate some unsystematic risk. To keep things simple, we can make our own ETF by allocating equal amounts of cash to every coin available on Alpaca Crypto. We can then regularly rebalance our fund to make sure we keep our exposure to each coin balanced. Let’s call this basket of assets our personal “Balanced Crypto ETF”!

Before we start placing orders, let’s first use crypto data to understand how well a strategy like this could work. One way to test how well a strategy performed in the past is by looking at its Sharpe Ratio. Let’s compare how buying and holding each individual coin compares against our Balanced Crypto ETF strategy.

Using the Market Data API

The Market Data API provides access to various types of market data, including bar, quote, and trade data. Bar data is OHLCV data, quote data is level 1 bid/ask, and trade data is the time and sales. These types of data are available for over 20 coins, including Bitcoin, Etherum, Litecoin, and many others.

As an example, let’s retrieve bar data for Bitcoin and see what it looks like. We can use the alpaca_client.get_crypto_bars method.

bars = alpaca_client.get_crypto_bars("BTCUSD", TimeFrame.Day, "2020-01-01", "2022-02-01").df
Price Data for Bitcoin in USD between 2020-01-01 and 2021-01-01

Calculating Historical Returns For Strategy

Let’s retrieve the prices for each of the coins available and compare their returns between 2020 and 2022. We can plot their returns to compare them. If we also plot the average of their returns over this period, we can get an idea of how our personal Balanced Crypto ETF would have performed.

These are the coins available.

coins = [

"AAVEUSD",   #	Aave (AAVE)
"BATUSD",    #	Basic Attention Token (BAT)
"BTCUSD",    #	Bitcoin (BTC)
"BCHUSD",    #	Bitcoin Cash (BCH)
"LINKUSD",   #	ChainLink Token (LINK)
"DAIUSD",    #	Dai (DAI)
"DOGEUSD",   #	Dogecoin (DOGE)
"ETHUSD",    #	Ethereum (ETH)
"GRTUSD",    #	Graph Token (GRT)
"LTCUSD",    #	Litecoin (LTC)
"MKRUSD",    #	Maker (MKR)
"MATICUSD",  #	Matic (MATIC)
"PAXGUSD",   #	PAX Gold (PAXG)
"SHIBUSD",   #	Shiba Inu (SHIB)
"SOLUSD",    #	Solana (SOL)
"SUSHIUSD",  #	Sushi (SUSHI)
"USDTUSD",   #	Tether (USDT)
"TRXUSD",    #	TRON (TRX)
"UNIUSD",    #	Uniswap Protocol Token (UNI)
"WBTCUSD",   # 	Wrapped BTC (WBTC)
"YFIUSD",    #  Yearn.Finance (YFI)

]

Let’s retrieve bar data between 2020 and 2022 for each of them and calculate their cumulative returns. To calculate the cumulative returns, we first calculate the daily returns as the percent change in daily closing prices. Then we can calculate the cumulative product of daily returns to calculate the cumulative return. Putting the cumulative return of each coin into a new dataframe, we can start to see how they compare. Before we plot, we calculate the average of each return as a new column, which will be our “Balanced Crypto ETF" column. This way we can see how each compares.

returns = {}

for coin in coins:
  bars = rest.get_crypto_bars(coin, TimeFrame.Day, "2020-01-01", "2022-01-01", exchanges=["FTXU"]).df
  bars['daily_return'] = bars['close'].pct_change()  
  cumulative_return = bars['daily_return'].add(1).cumprod().sub(1).dropna()
  returns[coin] = cumulative_return

df = pd.DataFrame(returns)

df['Balanced ETF'] = df.mean(axis=1)

df.plot()
Plots of Cumulative Returns of Various Cryptocurrencies between 2020 and 2022

There are a few coins that boasted very large returns during this period. The majority of the coins, including the Balanced Crypto ETF, show much lower returns compared to some coins like Solana, which produced over 5,000%+ in returns.

However, this graph can be misleading. Simply looking at the absolute returns of a coin over a period doesn’t paint a full picture of how good of an investment holding that coin was. From the graph, you can see that the coins that produced the largest gains also had some of the largest drawdowns. A better way to measure how effective an investment was is to look at its Sharpe Ratio, which provides a risk adjusted measure of return.

Comparing Strategies Using The Sharpe Ratio

Let’s compare the Sharpe Ratios of holding each coin against holding our Balanced Crypto ETF over the given period. The Sharpe Ratio provides a risk adjusted way to measuring returns.  It is calculated by taking the return of the coin and subtracting the risk free rate and dividing the difference by the standard deviation of the coins return over the same period. The risk free rate is the return we can produce with little risk. There are many option for choosing the risk free rate, such as 10 year treasury rate or the return of S&P500. Let's use the 10 year treasury rate which is about 2%.

risk_free_rate = 0.02
sharpe_ratio = (df.iloc[-1] - risk_free_rate) / df.std()

# sort in descending order
sharpe_ratio.sort_values(ascending=False)


We see that although our Balanced Crypto ETF, which had a Sharpe ratio of 2.25, did not have as high of a Sharpe ratio as some other coins, it outperformed many individual coins.

Creating Our Own "Balanced Crypto ETF"

First, begin evenly distributing by finding our account portfolio value and dividing by the number of coins. To get our account value, we need to use the get_account method to retrieve our account information. The account object the method returns contains information about our account value. Assuming that we have no other holdings and that we are not using any leverage, our buying power should be equal to our portfolio value. Let's use 95% of our buying power towards our ETF, leaving the rest in cash for any slippage or changes in margin requirement.

Let's evenly distribute our cash amongst each coin. We'll take our buying power and divide it by the number of coins to find how much allocation each coin requires. Then, we'll need to check how much we already have in holdings for that coin using the get_position_value method. Now, we can calculate the difference between how much allocation we have and how much allocation we require for our ETF to be balanced.

Using the submit_order method, we can submit orders for each coin for the notional amount we want to purchase. If we need to add coins to meet the desired allocation for a cryptocurrency, we will submit an order to buy. And vice versa if we need to remove coins to meet the desired allocation. To prevent orders for any small changes in allocation, we can create a threshold that the difference in allocation must surpass before we place an order to rebalance.

def rebalance_crypto_etf():
    account = alpaca_client.get_account()

	# delegate 95% of portfolio to ETF, leaving 5% cash on hand 
    # allows us to account for slippage or changes in margin requirements
    buying_power = float(account.portfolio_value) * 0.95
	
    # the rebalance threshold is the amount an allocation must deviate
    # before we place an order to rebalance it
    rebalance_threshold = 0.001 * buying_power
	
    # the desired allocation per coin
    desired_allocation = buying_power / len(coins)

    for coin in coins:
      
      # the current position size of that coin in our portfolio
      current_value = get_position_value(coin)
      
      # the difference between the desired allocation and existing allocation
      delta_alloc = desired_allocation - current_value
      
      # buy if delta is positive else sell
      side = "buy" if delta_alloc > 0 else "sell"
      
      notional = abs(delta_alloc)
      
      if notional > rebalance_threshold:
        alpaca_client.submit_order(symbol=coin, side=side, notional=notional)


def get_position_value(symbol):
	"""Returns the market value of holdings in a given symbol."""
    try:
        position = alpaca_client.get_position(symbol)
        return float(position.market_value)
    except:
		# if there is no position open, a 404 error is thrown
        # 0 market value for that symbol
        return 0


We can call this method whenever we want to rebalance, whether that’s weekly, monthly or yearly.

Scheduling For Rebalance

We want to maintain an equal allocation to each coin, which requires us to rebalance regularly. There are a few ways to schedule our rebalance function to run. One option is to use the python schedule library. The following example rebalances every Monday at 10:30 AM. To install schedule run pip install schedule.

import schedule
import time

schedule.every().monday.at("10:30").do(rebalance_crypto_etf)

while True:
    schedule.run_pending()
    time.sleep(1)


We can also use cron jobs to run our python script at a specified schedule. You can learn about cronjobs in this great article.

Conclusion

Diversifying your portfolio may be a great way to help mitigate nonsystematic risk. We’ve shown you how to use the Crypto API to select from a range of coins and create a basket that’s right for you. And this is just one way to use the Crypto API – there are countless different strategies you can explore and apps you can build. Happy coding!

*Please note this is not an actual exchange-traded fund (“ETF”) managed by a registered investment advisor; rather, this feature can be used to distribute your own investment portfolio across supported crypto assets based on your preferred allocation for each coin.


Please note there is no guarantee that any strategy will achieve its objectives and past performance does not guarantee future results.

Cryptocurrency services are made available by Alpaca Crypto LLC ("Alpaca Crypto"), a FinCEN registered money services business (NMLS # 2160858), and a wholly-owned subsidiary of AlpacaDB, Inc. Alpaca Crypto is not a member of SIPC or FINRA. Cryptocurrencies are not stocks and your cryptocurrency investments are not protected by either FDIC or SIPC. Depending on your location, cryptocurrency services may be provided by West Realm Shires Services, Inc., d/b/a FTX US (NMLS #1957771).

This is not an offer, solicitation of an offer, or advice to buy or sell securities or cryptocurrencies, or open a brokerage account or cryptocurrency account in any jurisdiction where Alpaca Securities, Alpaca Crypto, or FTX US respectively, are not registered or licensed, as applicable.

Cryptocurrency is highly speculative in nature, involves a high degree of risks, such as volatile market price swings, market manipulation, flash crashes, and cybersecurity risks. Cryptocurrency is not regulated or is lightly regulated in most countries. Cryptocurrency trading can lead to large, immediate and permanent loss of financial value. You should have appropriate knowledge and experience before engaging in cryptocurrency trading. For additional information, please click here.


Please see alpaca.markets and Alpaca’s Disclosure Library for more information.

CryptoMarket Data APITrading API