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)

SymbolNameRatingScoreDevScoreMaturityUtilityLastRefresh
StringStringStringInt64Int64Int64Int64String
1BTCBitcoinSuperb9108688979652021-03-26 00:00:00
2ETHEthereumSuperb9739668969972021-03-26 00:00:00
3ADACardanoSuperb9649699319662021-03-26 00:00:00
4BNBBinance CoinAttractive8347459019322021-03-26 00:00:00
5XRPXRPAttractive8428818297942021-03-26 00:00:00
6THETATHETACaution5887269153532021-03-26 00:00:00
7LTCLitecoinAttractive7756528999052021-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 ThetaToken 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 the Flipside Crypto website.

Crypto 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)

timestampopen (USD)high (USD)low (USD)close (USD)open (USD)_1high (USD)_1
DateAnyAnyAnyAnyAnyAny
12018-08-317735.677750.05880.07011.217735.677750.0
22018-09-307011.217410.06111.06626.577011.217410.0
32018-10-316626.577680.06205.06371.936626.577680.0
42018-11-306369.526615.153652.664041.326369.526615.15
52018-12-314041.274312.993156.263702.94041.274312.99
returnPlot = plot(prices[!, :timestamp], prices[!, :CumReturn], group=prices[!, :Symbol],
                  title="Cumulative 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)

SymbolMeanVolumeNameRatingScoreDevScoreMaturityUtility
StringFloat64String?String?Int64?Int64?Int64?Int64?
1BTC2.473e10BitcoinSuperb910868897965
2ETH9.6248e9EthereumSuperb973966896997
3ADA2.6184e9CardanoSuperb964969931966
4BNB3.7598e9Binance CoinAttractive834745901932
5XRP3.28003e9XRPAttractive842881829794
6THETA6.36549e8THETACaution588726915353
7LTC1.71448e9LitecoinAttractive775652899905

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!