Plotting Market Data from AlphaVantage.jl with Gnuplot.jl

The following description on how to get data from AlphaVantage is mainly based on Dean Markwick post AlphaVantage.jl - Getting Market Data into Julia.

AlphaVantage

AlphaVantage is a market data provider that is nice enough to provide free access to a wide variety of data. Available functionality

  • Stock data at both intraday, daily, weekly and monthly frequencies.

  • Technical indicators for stocks.

  • FX rates at both intraday, daily, weekly and monthly frequencies.

  • Crypto currencies, again, at the intraday, daily, weekly and monthly time scales.

The package is designed to replicate the API functions from the AlphaVantage documentation, so you can look up any of the functions in their documentation here and find the equivalent in this Julia package. If something is missing or isn’t working correctly, raise an issue on Github here.

Gnuplot.jl

Here, the goal is to simply show how the data can be plotted with this package. Gnuplot.jl is a simple package able to send both data and commands from Julia to an underlying gnuplot process. Its main purpose it to provide a fast and powerful data visualization framework, using an extremely concise Julia syntax.

Let's get ready with all the packages that we will need.

Getting gnuplot and Julia packages

If you are in Linux, usually doing the following is enough to get gnuplot. 

apt-get -qq update
apt-get install gnuplot gnuplot-nox
4.8s
Bash in Julia

Remember, after you also need to install Gnuplot.jl, with add Gnuplot in the Julia  repl, plus some extra packages for the market data.

]add Dates DataFrames DataFramesMeta Gnuplot AlphaVantage
11.9s

For easy plotting I did some recipies in Gnuplot (not all cases but most), so that our exploration becomes easier.  So, if you try to reproduce these plots don't forget to include the script plotMarketData.jl and raw_to_df.jl to convert our data into DataFrames.

rawtodf.jl
plotMarketData.jl

Loading all packages

# ENV["ALPHA_VANTAGE_API_KEY"] = "your key" # please get one!
using AlphaVantage, DataFrames, Dates, DataFramesMeta
using Gnuplot
import Gnuplot: PlotElement, DatasetText
include(
rawtodf.jl
)
include(
plotMarketData.jl
)
24.8s
hline_at (generic function with 1 method)
Gnuplot.gpversion()
0.7s
v"5.2.0"

Stocks

AlphaVantage provides daily, weekly and monthly historical stock data from 2000 right up to when you call the function. With the adjusted functions you also get dividends and adjusted closing prices to account for these dividends.

tslaRaw = time_series_daily_adjusted("TSLA", outputsize="full", datatype="csv");
12.6s
tsla = raw_to_dataframe(tslaRaw)
first(tsla, 5)
4.7s
timestampopenhighlowcloseadjusted_closevolumedividend_amountsplit_coefficient
2020-07-101396.01548.921376.011544.651544.65233464000.01.0
2020-07-091396.991408.561351.281394.281394.28117183000.01.0
2020-07-081405.01417.261311.341365.881365.88163302000.01.0
2020-07-071405.011429.51336.711389.861389.86214933000.01.0
2020-07-061276.691377.791266.041371.581371.58205703000.01.0
5 items

Then, our first plot looks like

@gp plot(tsla, :timestamp, :open)
save(term = "svg size 650,400", output = "/results/TSLAopen.svg")
6.7s

And something really great about Gnuplot is that you can update your plot again by using @gp :- as follows

@gp plot(tsla, :timestamp, :open, lc = :red, leg_p ="l")
@gp :- plot!(tsla, :timestamp, :close)
@gp :- "set title font ',15' 'TSLA'" :-
@gp :- "set xlab font ',15' 'Date Time'" "set ylab font ',15' 'Price'"
save(term = "svg size 650,450", output = "/results/TSLAopen_close.svg")
0.9s

S&P500

A very familiar stock is S&P 500, so here we are getting the daily S&P500 data and plotting it as

SP500Raw = time_series_daily("SPY", datatype="csv")
SP500 = raw_to_dataframe(SP500Raw, indc = 4)
first(SP500, 5)
0.5s
timestampopenhighlowclosevolume
2020-07-10314.31317.88312.76317.5957454400
2020-07-09316.84317.1310.68314.3883079100
2020-07-08314.61316.3312.7316.1854202600
2020-07-07315.38317.52313.37313.7882583400
2020-07-06316.37317.68315.56317.0561149300
5 items
@gp plot(SP500, :timestamp, :open, title = "SP500", leg_p = "b", rot_xtics=0) :-
@gp :- plot!(SP500, :timestamp, :close, :red) :-
@gp :- plot!(SP500, :timestamp, :low) :-
@gp :- plot!(SP500, :timestamp, :high)
@gp :- "set xlab font ',15' 'Date'" "set ylab font ',15' 'Price'"
save(term = "svg size 650,400", output = "/results/SP500.svg")
0.7s

Or, if you have all your prices, by default you can get the candle-bars as follows

plot(SP500, :timestamp, rot_xtics=-45)
@gp :- "set title 'SP500'" :-
@gp :- "set xlab font ',15' 'Date'" "set ylab font ',15' 'Price'"
save(term = "svg size 650,450", output = "/results/SP500_candle.svg")
1.9s

And with a different color

plot(SP500, :timestamp, box_color = "orange",rot_xtics=-45)
@gp :- "set title 'SP500'" :-
@gp :- "set xlab font ',15' 'Date'" "set ylab font ',15' 'Price'"
save(term = "svg size 650,450", output = "/results/SP500_candle_color.svg")
0.2s

And for a smaller interval

plot(SP500, :timestamp,ini_date ="2020-03-01", end_date = "2020-04-01",
    box_color = "black", leg_p = "t")
@gp :- "set title 'SP500'"
@gp :- "set xlab font ',15' 'Date'" "set ylab font ',15' 'Price'"
save(term = "svg size 650,450", output = "/results/SP500_candle_zoom.svg")
0.3s

And you can even add a new line on top...

plot(SP500, :timestamp,ini_date ="2020-03-01", end_date = "2020-04-01",
    box_color = "black", leg_p = "t")
@gp :- plot!(SP500, :timestamp, :open)
@gp :- "set title 'SP500'"
@gp :- "set xlab font ',15' 'Date'" "set ylab font ',15' 'Price'"
save(term = "svg size 650,450", output = "/results/SP500_candle_open.svg")
0.3s

Shaded area under price

plot(SP500, :timestamp, :close, "gold", :plasma; lcol = "orange", α =0.95)
@gp :- "set title 'SP500'"
@gp :- "set xlab font ',15' 'Date'" "set ylab font ',15' 'Price'"
save(term = "svg size 650,450", output = "/results/SP500_shaded.svg")
3.3s

Note: if you use any another terminal, not svg, the transparencies look nicer.

And as before, you can add more lines on top:

plot(SP500, :timestamp, :close, "gold", :plasma; lcol = "orange", α =0.952)
@gp :- plot!(SP500, :timestamp, :open, :black)
@gp :- plot!(SP500, :timestamp, :high, :blue)
@gp :- "set title 'SP500'"
@gp :- "set xlab font ',15' 'Date'" "set ylab font ',15' 'Price'"
save(term = "svg size 650,450", output = "/results/SP500_shaded_lines.svg")
0.5s

Intraday

What separates AlphaVantage from say google or yahoo finance data is the intraday data. They provide high frequency bars at intervals from 1 minute to an hour. The only disadvantage is that the maximum amount of data appears to be 5 days for a stock. Still better than nothing!

tslaIntraRaw = AlphaVantage.time_series_intraday("TSLA", "1min", 
    outputsize="full", datatype="csv")
tslaIntra = intra_to_dataframe(tslaIntraRaw)
5.6s

Be careful with the number of days before!

tslaIntraDay = @where(tslaIntra, :DateTime .> DateTime(today()-Day(2)))
first(tslaIntraDay,4)
0.3s
timestampopenhighlowclosevolumeDateTime
2020-07-10 20:00:001541.751542.01541.751542.016542020-07-10T20:00:00
2020-07-10 19:59:001542.341542.981542.01542.9816692020-07-10T19:59:00
2020-07-10 19:58:001543.01543.01542.11542.111342020-07-10T19:58:00
2020-07-10 19:57:001544.01544.01544.01544.011692020-07-10T19:57:00
4 items
plot(tslaIntraDay, :DateTime, :close, "#cc0000", :plasma; 
    lcol = "#333333", α =0.92, rot_xtics = -45)
@gp :- "set title font ',15' 'TSLA Intraday $(today()-Day(1))'" :-
@gp :- "set xlab font ',15' 'Date Time'" "set ylab font ',15' 'Price'"
save(term = "svg size 650,450", output = "/results/TSLAintraday.svg")
0.4s

or no shading at all

@gp plot(tslaIntra, :DateTime, :open )
@gp :- "set title 'TSLA Intraday'"
@gp :- "set xlab font ',15' 'Date Time'" "set ylab font ',15' 'Price'"
save(term = "svg size 650,450", output = "/results/TSLAintraday_noshade.svg")
0.6s

Technical Indicators

AlphaVantage also provide a wide range of technical indicators. In this example we are using the Relative Strength Index.

rsiRaw = AlphaVantage.RSI("TSLA", "1min", 10, "open", datatype="csv")
rsiDF = DataFrame(rsiRaw[1])
rsiDF = rename(rsiDF, Symbol.(vcat(rsiRaw[2]...)))
rsiDF.time = DateTime.(rsiDF.time, "yyyy-mm-dd HH:MM:SS")
rsiDF.RSI = Float64.(rsiDF.RSI)
rsiSub = @where(rsiDF, :time .> DateTime(today() - Day(2)))
first(rsiSub,5)
5.3s
timeRSI
2020-07-10T20:00:0039.0232
2020-07-10T19:59:0043.6106
2020-07-10T19:58:0049.4649
2020-07-10T19:57:0060.5484
2020-07-10T19:56:0075.4619
5 items
minimum(rsiSub[!,:time]), maximum(rsiSub[!,:time])
0.6s
(2020-07-10T04:16:00, 2020-07-10T20:00:00)
iniDate = "2020-07-10T04:16:00"
lastDate = "2020-07-10T20:00:00"
plot(rsiSub, :time, :RSI, "", :lajolla; lcol = "black", α =0.85)
@gp :- plot(iniDate, lastDate, 30; label = "Oversold")
@gp :- plot(iniDate, lastDate, 70, :red; label = "Overbought")
@gp :- "set title 'RSI'"
@gp :- "set xlab font ',15' 'Date Time'"
save(term = "svg size 650,450", output = "/results/RSI.svg")
0.5s

In this case, adding the threshold lines make a nice channel that the value falls between.

Sector Performance

AlphaVantage also provides the sector performance on a number of timescales through one API call.

sectorRaw = AlphaVantage.sector_performance()
sectorRaw["Rank F: Year-to-Date (YTD) Performance"]
2.8s
Dict{String,Any} with 11 entries: "Health Care" => "-1.20%" "Financials" => "-23.74%" "Consumer Discretionary" => "14.16%" "Materials" => "-5.43%" "Consumer Staples" => "-4.27%" "Energy" => "-40.78%" "Real Estate" => "-9.57%" "Information Technology" => "18.01%" "Utilities" => "-10.57%" "Communication Services" => "5.92%" "Industrials" => "-16.42%"

Great year for IT, not so great for energy.

Forex

Moving into the foreign exchange market, again, AlphaVantage provide multiple time scales and many currencies.

eurgbpRaw = AlphaVantage.fx_weekly("EUR", "GBP", datatype="csv");
eurgbp = DataFrame(eurgbpRaw[1])
eurgbp = rename(eurgbp, Symbol.(vcat(eurgbpRaw[2]...)))
eurgbp.Date = Date.(eurgbp.timestamp)
eurgbp.open = Float64.(eurgbp.open)
eurgbp.high = Float64.(eurgbp.high)
eurgbp.low = Float64.(eurgbp.low)
eurgbp.close = Float64.(eurgbp.close);
1.8s
@gp plot(eurgbp, :Date, :open, title="EURGBP")
@gp :- "set xlab font ',15' 'Date'" "set ylab font ',15' 'Price'"
save(term = "svg size 650,450", output = "/results/EURGBP.svg")
0.4s

Which looks great for a liquid currency like EURGBP, but they have a whole host of currencies so don’t limit yourself to just the basics, explore some NDF’s.

usdkrwRaw = AlphaVantage.fx_monthly("USD", "KRW", datatype="csv");
usdkrw = DataFrame(usdkrwRaw[1])
usdkrw = rename(usdkrw, Symbol.(vcat(usdkrwRaw[2]...)))
#usdkrw = 
usdkrw.Date = Date.(usdkrw.timestamp)
usdkrw.open = Float64.(usdkrw.open)
usdkrw.high = Float64.(usdkrw.high)
usdkrw.low = Float64.(usdkrw.low)
usdkrw.close = Float64.(usdkrw.close);
2.2s
@gp plot(usdkrw, :Date, :open, title="USDKRW")
@gp :- "set xlab font ',15' 'Date Time'" "set ylab font ',15' 'Price'"
save(term = "svg size 650,450", output = "/results/USDKRW.svg")
0.2s
plot(usdkrw, :timestamp)
@gp :- "set title 'USDKRW'"
@gp :- "set xlab font ',15' 'Date'" "set ylab font ',15' 'Price'"
save(term = "svg size 650,450", output = "/results/USDKRW_candle.svg")
0.9s

FX Intraday

Again, intraday data is available for the FX pairs.

usdcadRaw = AlphaVantage.fx_intraday("USD", "CAD", datatype="csv");
usdcad = DataFrame(usdcadRaw[1])
usdcad = rename(usdcad, Symbol.(vcat(usdcadRaw[2]...)))
usdcad.timestamp = DateTime.(usdcad.timestamp, "yyyy-mm-dd HH:MM:SS")
usdcad.open = Float64.(usdcad.open);
0.6s
plot(usdcad, :timestamp, :open, "", :roma;  α =0.9)
@gp :- "set title 'USDCAD'"
@gp :- "set xlab font ',15' 'Date Time'" "set ylab font ',15' 'Price'"
save(term = "svg size 650,450", output = "/results/USDCAD.svg")
0.3s

Crypto

Now for digital currencies. The API follows the same style as traditional currencies and again has more digital currencies than you can shake a stick at. Again daily, weekly and monthly data is available plus a ‘health-index’ monitor that reports how healthy a cryptocurrency is based on different features.

ethRaw = AlphaVantage.digital_currency_daily("ETH", "USD", datatype="csv")
ethHealth = AlphaVantage.crypto_rating("ETH");
titleString = ethHealth["Crypto Rating (FCAS)"];
1.6s

The health rating looks like that, four scores, a qualitative rating and some meta information. The price charts look like as you would expect.

eth = DataFrame(ethRaw[1])
eth = rename(eth, Symbol.(vcat(ethRaw[2]...)), makeunique=true)
eth[!,:timestamp] = Dates.Date.(eth[!,:timestamp])
eth[!,Symbol("open (USD)")] = Float64.(eth[!, Symbol("open (USD)")])
first(eth, 6)
0.3s
timestampopen (USD)high (USD)low (USD)close (USD)open (USD)_1high (USD)_1low (USD)_1close (USD)_1volumemarket cap (USD)
2020-07-12239.19239.99239.0239.83239.19239.99239.0239.838263.128263.12
2020-07-11241.27241.67237.54239.19241.27241.67237.54239.19294476.0294476.0
2020-07-10241.97242.16235.72241.26241.97242.16235.72241.26455025.0455025.0
2020-07-09246.94247.9237.88241.98246.94247.9237.88241.98647642.0647642.0
2020-07-08239.39248.88237.78246.95239.39248.88237.78246.95958186.0958186.0
2020-07-07241.6243.77234.4239.39241.6243.77234.4239.39600425.0600425.0
6 items
plot(eth, :timestamp, Symbol("open (USD)"), "", :devon; lcol = "black",
  α =0.952)
@gp :- "set title 'Ethereum'" :-
@gp :- "set xlab font ',15' 'Date'" "set ylab font ',15' 'Price'"
save(term = "svg size 650,450", output = "/results/Ethereum.svg")
0.4s

Conclusion

As you can see it's pretty easy to explore financial data by using AlphaVantage and Gnuplot. So go grab yourself an API key, download these packages and see what you can do.

Find me on twitter as @LazarusAlon

Runtimes (1)