Crypto Data using AlphaVantatge.jl
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
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 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)
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="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)
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)
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...)
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!