Crypto Data using AlphaVantatge.jl

By: Dean Markwick's Blog -- Julia

Re-posted from: https://dm13450.github.io/2021/03/27/CryptoAlphaVantage.html

Julia 1.6 is hot off the press, so I’ve installed it and fired off this quick blog post to give 1.6 a test drive. So far, so good and there is a real decrease now in the latencies in both loading up packages and getting things going.

AlphaVantage have data on cryptocurrencies and not just stocks and fx. Each of which are implemented in AlphaVantage.jl. This is a simple blogpost that takes you through each function and how it might be useful to analyse cryptocurrencies.

Firstly, what coins are available? Over 500 (542 to be precise). Now as a crypto tourist, I’m only really familiar with the most popular ones that are causing the headlines. So I’ve taken the top 10 from coinmarketcap and will use those to demonstrate what AlphaVantage can do.

using AlphaVantage
using Plots
using DataFrames, DataFramesMeta
using CSV, Dates, Statistics

ccys = ["BTC", "ETH", "ADA", "DOT", "BNB", "USDT", "XRP", "UNI", "THETA", "LTC"]

FCAS Health Index from Flipside Crypto

AlphaVantage have partnered with Flipside Crypto to provide their ratings of different coins. This is designed to give some further info on different coins rather than just looking at what recently increased massively.

ratings = crypto_rating.(ccys);

Simple broadcasted call to get the ratings for each of the 10 currencies above. We format the response into a dataframe and get a nice table out. Not all the coins have a rating, so we have to filter out any empty ratings.

inds = findall(.!isempty.(ratings))
ratingsFrame = vcat(map(x->DataFrame(x["Crypto Rating (FCAS)"]), ratings[inds])...)
rename!(ratingsFrame, Symbol.(["Symbol", "Name", "Rating", "Score", "DevScore", "Maturity", "Utility", "LastRefresh", "TZ"]))
for col in (:Score, :DevScore, :Maturity, :Utility)
    ratingsFrame[!, col] .= parse.(Int64, ratingsFrame[!, col])
end
ratingsFrame

7 rows × 9 columns (omitted printing of 1 columns)

Symbol Name Rating Score DevScore Maturity Utility LastRefresh
String String String Int64 Int64 Int64 Int64 String
1 BTC Bitcoin Superb 910 868 897 965 2021-03-26 00:00:00
2 ETH Ethereum Superb 973 966 896 997 2021-03-26 00:00:00
3 ADA Cardano Superb 964 969 931 966 2021-03-26 00:00:00
4 BNB Binance Coin Attractive 834 745 901 932 2021-03-26 00:00:00
5 XRP XRP Attractive 842 881 829 794 2021-03-26 00:00:00
6 THETA THETA Caution 588 726 915 353 2021-03-26 00:00:00
7 LTC Litecoin Attractive 775 652 899 905 2021-03-26 00:00:00

Three superb, three attractive and one caution. THETA gets a lower utility score which is dragging down its overal rating. By the looks of it, THETA is some sort of streaming/YouTube-esque project, get paid their token by giving your excess computing power to video streams. There website is here and I’ll let you judge whether they deserve that rating.

To summarise briefly each of the ratings is on a 0 to 1000 scale in three different areas:

  • Developer Score (DevScore)

Things like code changes, improvements all taken from the repositories of the coins.

  • Market Maturity (Maturity)

This looks at the market conditions around the coin, so things like liquidity and volatility.

  • User Activity (Utility)

On chain activities, network activity and transactions, so is the coin being used for something actually useful. Hence why you can see why ETH is ranked the highest here.

More details are on their website here.

Timeseries Data

AlphaVantage also offer the usual time series data at daily, weekly and monthly frequencies. Hopefully you’ve read my other posts (basic market data and fundamental data), so this is nothing new!

Now for each 10 tokens we can grab their monthly data and calculate some stats and plot some graphs.

monthlyData = digital_currency_monthly.(ccys[inds], datatype = "csv");

Again formatting the returned data into a nice dataframe gives us a monthly view of the price action for each of the currencies. I format the date column, calculate the monthly log return and cumulative log return.

function format_data(x, ccy)
    df = DataFrame(x[1])
    rename!(df, Symbol.(vec(x[2])), makeunique=true)
    df[!, :timestamp] = Date.(df[!, :timestamp])
    sort!(df, :timestamp)
    df[!, :Return] = [NaN; diff(log.(df[!, Symbol("close (USD)")]))]
    df[!, :CumReturn] = [0; cumsum(diff(log.(df[!, Symbol("close (USD)")])))]
    df[!, :Symbol] .= ccy
    df
end

prices = vcat(map(x -> format_data(x[1], x[2]), zip(monthlyData, ccys[inds]))...)
first(prices, 5)

5 rows × 14 columns (omitted printing of 7 columns)

timestamp open (USD) high (USD) low (USD) close (USD) open (USD)_1 high (USD)_1
Date Any Any Any Any Any Any
1 2018-08-31 7735.67 7750.0 5880.0 7011.21 7735.67 7750.0
2 2018-09-30 7011.21 7410.0 6111.0 6626.57 7011.21 7410.0
3 2018-10-31 6626.57 7680.0 6205.0 6371.93 6626.57 7680.0
4 2018-11-30 6369.52 6615.15 3652.66 4041.32 6369.52 6615.15
5 2018-12-31 4041.27 4312.99 3156.26 3702.9 4041.27 4312.99
returnPlot = plot(prices[!, :timestamp], prices[!, :CumReturn], group=prices[!, :Symbol],
                  title="Cummulative Return",
                  legend=:topleft)
mcPlot = plot(prices[!, :timestamp], 
              prices[!, Symbol("market cap (USD)")] .* prices[!, Symbol("close (USD)")], 
              group=prices[!, :Symbol],
              title="Market Cap",
              legend=:none)

plot(returnPlot, mcPlot)

svg

There we go, solid cumulative monthly returns (to the moon!) but bit of a decline in market cap recently after a week of negative returns. If you want higher frequencies there is always

  • digital_currency_daily
  • digital_currency_weekly

which will return the same type of data, just indexed differently.

Is the Rating Correlated with Monthly Trading Volume?

We’ve got two data sets, now we want to see if we can explain some the crypto scores with how much is traded each month. For this we simply take the monthly data, average the monthly volume traded and join it with the ratings dataframe.

gdata = groupby(prices, :Symbol)
avgprices = @combine(gdata, MeanVolume = mean(:volume .* cols(Symbol("close (USD)"))))
avgprices = leftjoin(avgprices, ratingsFrame, on=:Symbol)

7 rows × 10 columns (omitted printing of 2 columns)

Symbol MeanVolume Name Rating Score DevScore Maturity Utility
String Float64 String? String? Int64? Int64? Int64? Int64?
1 BTC 2.473e10 Bitcoin Superb 910 868 897 965
2 ETH 9.6248e9 Ethereum Superb 973 966 896 997
3 ADA 2.6184e9 Cardano Superb 964 969 931 966
4 BNB 3.7598e9 Binance Coin Attractive 834 745 901 932
5 XRP 3.28003e9 XRP Attractive 842 881 829 794
6 THETA 6.36549e8 THETA Caution 588 726 915 353
7 LTC 1.71448e9 Litecoin Attractive 775 652 899 905

Visually, lets just plot the different scores on the x-axis and the monthly average volume on the y-axis. Taking logs of both variables stops BTC dominating the plots.

scorePlots = [plot(log.(avgprices[!, x]), 
                   log.(avgprices.MeanVolume), 
                   seriestype=:scatter, 
                   series_annotations = text.(avgprices.Symbol, :bottom),
                   legend=:none, 
                   title=String(x)) 
    for x in (:Score, :DevScore, :Maturity, :Utility)]
plot(scorePlots...)

svg

Solid linear relationship in the score and dev score metrics, not so much for the maturity and utility scores. Of course, as this is a log-log plot a linear relationship indicates power law behaviour.

Side note though, the graphs are a bit rough around the edges, labels are overlapping and even crossing though the axis. Julia needs a ggrepel equivalent.

Summary

Much like the other functions in AlphaVantage.jl everything comes through quite nicely and once you have the data its up to you to find something interesting!