Loading...

Commodities

This example uses the commodities dataset to predict the price of different commodities. You can download the Jupyter Notebook of the study here.

  • date: Date of the record.

  • Gold: Price per ounce of Gold.

  • Oil: Price per Barrel - West Texas Intermediate (WTI).

  • Spread: Interest Rate Spreads.

  • Vix: The CBOE Volatility Index (VIX) is a measure of expected price fluctuations in the SP500 Index options over the next 30 - days.

  • Dol_Eur: How much $1 US is in euros.

  • SP500: The S&P 500, or simply the S&P, is a stock market index that measures the stock performance of 500 large companies - listed on stock exchanges in the United States.

We will follow the data science cycle (Data Exploration - Data Preparation - Data Modeling - Model Evaluation - Model Deployment) to solve this problem.

Initialization

This example uses the following version of VerticaPy:

import verticapy as vp

vp.__version__
Out[2]: '1.1.0'

Connect to Vertica. This example uses an existing connection called VerticaDSN. For details on how to create a connection, see the Connection tutorial. You can skip the below cell if you already have an established connection.

vp.connect("VerticaDSN")

Let’s create a Virtual DataFrame of the dataset.

from verticapy.datasets import load_commodities

commodities = load_commodities()
commodities.head(100)
📅
date
Date
100%
...
123
Dol_Eur
Float
100%
123
SP500
Float
100%
11986-11-01...0.967399999999543249.220001
21987-02-01...0.882600000000821284.200012
31987-05-01...0.861100000000079290.100006
41987-08-01...0.89600000000064329.799988
51987-10-01...0.868599999999788251.789993
61987-12-01...0.791400000000067247.080002
71988-02-01...0.822000000000116267.820007
81988-03-01...0.810900000000402258.890015
91988-09-01...0.900299999999334271.910004
101988-11-01...0.844499999999243273.700012
111989-02-01...0.888899999999921288.859985
121989-06-01...0.955400000000736317.980011
131989-07-01...0.914000000000669346.079987
141989-11-01...0.893899999999121345.98999
151989-12-01...0.856499999999869353.399994
161990-02-01...0.820799999999508331.890015
171990-10-01...0.739799999999377304.0
181991-01-01...0.736699999999473343.929993
191991-04-01...0.826699999999619375.339996
201991-05-01...0.83389999999963389.829987
211992-03-01...0.812700000000404403.690002
221992-05-01...0.78859999999986415.350006
231992-07-01...0.729799999999159424.209991
241992-10-01...0.755199999999604418.679993
251992-11-01...0.807199999999284431.350006
261992-12-01...0.807199999999284435.709991
271993-03-01...0.848400000000766451.670013
281993-04-01...0.820100000000821440.190002
291993-05-01...0.821200000000317450.190002
301993-06-01...0.844300000000658450.529999
311993-08-01...0.882400000000416463.559998
321994-04-01...0.877300000000105450.910004
331994-06-01...0.845699999999852444.269989
341994-07-01...0.818499999999404458.26001
351995-07-01...0.743437999999514562.059998
361996-03-01...0.780428570000368645.5
371996-06-01...0.797715009999592670.630005
381996-11-01...0.78265237999949757.02002
391996-12-01...0.799684999999954740.73999
401997-01-01...0.822170909999841786.159973
411998-03-01...0.9222545499997071101.75
421998-04-01...0.9165400000001681111.75
431998-08-01...0.90782380952381957.280029
441998-10-01...0.8383181818181821098.670044
451999-07-01...0.9662251999545451328.719971
461999-08-01...0.94356753751320.410034
472000-06-01...1.052983719181821454.599976
482000-09-01...1.148397447571431436.51001
492000-12-01...1.110847240651320.280029
502001-02-01...1.08538143931239.939941
512001-04-01...1.1188749661249.459961
522001-05-01...1.1434916821255.819946
532001-07-01...1.160932856590911211.22998
542001-09-01...1.095831355551040.939941
552002-08-01...1.02246676136364916.070007
562002-10-01...1.01855763682609885.76001
572003-05-01...0.864283957363636963.590027
582003-09-01...0.888519456863636995.969971
592004-05-01...0.8324215129047621120.680054
602005-02-01...0.767651335051203.599976
612005-04-01...0.7726796172857141156.849976
622005-08-01...0.8133932101304351220.329956
632005-11-01...0.8479040993636361249.47998
642006-05-01...0.7829057142173911270.089966
652006-08-01...0.7806007433043481303.819946
662006-09-01...0.7853484189523811335.849976
672007-09-01...0.718849564051526.75
682007-12-01...0.686773225551468.359985
692008-03-01...0.6440975905714291322.699951
702008-04-01...0.6350929536363641385.589966
712008-05-01...0.6425454545454551400.380005
722008-10-01...0.753347826086956968.75
732009-07-01...0.709826086956522987.47998
742009-11-01...0.6702333333333331095.630005
752010-03-01...0.7371169.430054
762010-05-01...0.7954285714285711089.410034
772010-06-01...0.8189545454545451030.709961
782010-09-01...0.7639090909090911141.199951
792011-03-01...0.7135652173913041325.829956
802011-04-01...0.6917142857142861363.609985
812012-04-01...0.7599523809523811397.910034
822012-08-01...0.8061739130434781406.579956
832012-10-01...0.7706086956521741412.160034
842013-01-01...0.7521498.109985
852013-02-01...0.749551514.680054
862013-03-01...0.7720476190476191569.189941
872013-05-01...0.7707142857142861630.73999
882013-10-01...0.7330056521739131756.540039
892014-02-01...0.7317461859.449951
902014-04-01...0.7240890909090911883.949951
912014-05-01...0.7281081818181821923.569946
922014-08-01...0.750922003.369995
932014-10-01...0.7890443478260872018.050049
942014-11-01...0.8013682067.560059
952015-02-01...0.8805632104.5
962015-05-01...0.8961171428571432107.389893
972015-08-01...0.8983647619047621972.180054
982015-09-01...0.8914286363636361920.030029
992016-04-01...0.8818176190476192065.300049
1002016-11-01...0.9276704545454542198.810059

Data Exploration and Preparation

Let’s explore the data by displaying descriptive statistics of all the columns.

commodities.describe(method = "all", unique = True)
...
123
"SP500"
Float
100%
📅
"date"
Date
100%
dtype...floatdate
percent...100100
count...416416
top...304.01986-01-01
top_percent...0.4810.24
avg...1190.84896648798[null]
stddev...752.215482101545[null]
min...211.7799991986-01-01
approx_25%...467.657494[null]
approx_50%...1132.5[null]
approx_75%...1454.767487[null]
max...3500.3100592020-08-01
range...3288.5300612631
empty...[null][null]
unique...414.0413.0

We have data from January 1986 to the beginning of August 2020. We don’t have any missing values, so our data is already clean.

Let’s draw the different variables.

commodities.plot(ts = "date")

Some of the commodities have an upward monotonic trend and some others might be stationary. Let’s use Augmented Dickey-Fuller tests to check our hypotheses.

from verticapy.machine_learning.model_selection.statistical_tests import adfuller
from verticapy.core.tablesample import TableSample

fuller = {}
for commodity in ["Gold", "Oil", "Spread", "Vix", "Dol_Eur", "SP500"]:
    result = adfuller(
        commodities,
        column = commodity,
        ts = "date",
        p = 3,
        with_trend = True,
    )
    fuller["index"] = result["index"]
    fuller[commodity] = result["value"]
fuller = TableSample(fuller)
fuller
...
Dol_Eur
SP500
ADF Test Statistic...-2.7980161815599516-0.09469625542100038
p_value...0.005386622700619620.924602810088177
# Lags used...33
# Observations Used...416416
Critical Value (1%)...3.983.98
Critical Value (2.5%)...-3.68-3.68
Critical Value (5%)...-3.42-3.42
Critical Value (10%)...-3.13-3.13
Stationarity (alpha = 1%)...

As expected: The price of gold and the S&P 500 index are not stationary. Let’s use the Mann-Kendall test to confirm the trends.

from verticapy.machine_learning.model_selection.statistical_tests import mkt

kendall = {}
for commodity in ["Gold", "SP500"]:
    result = mkt(
        commodities,
        column = commodity,
        ts = "date",
    )
    kendall["index"] = result["index"]
    kendall[commodity] = result["value"]
kendall = TableSample(kendall)
kendall
...
Gold
SP500
Mann Kendall Test Statistic...15.00107543372596424.886617341458717
S...42504.070513.0
STDS...2833.330196076692833.33001960591
p_value...7.223928538831201e-511.0387121156452156e-136
Monotonic Trend...
Trend...increasingincreasing

Our hypothesis is correct. We can also look at the correlation between the elapsed time and our variables to see the different trends.

import verticapy.sql.functions as fun

commodities["elapsed_days"] = commodities["date"] - fun.min(commodities["date"])._over()
commodities.corr(focus = "elapsed_days")

In the last plot, it’s a bit hard to tell if Spread is stationary. Let’s draw it alone.

commodities["Spread"].plot(ts = "date")

We can see some sudden changes, so let’s smooth the curve.

commodities.rolling(
    func = "avg",
    window = (-20, 0),
    columns = "Spread",
    order_by = ["date"],
    name = "Spread_smooth",
)
commodities["Spread_smooth"].plot(ts = "date")

After each local minimum, there is a local maximum. Let’s look at the number of lags needed to keep most of the information. To visualize this, we can draw the autocorrelation function (ACF) and partial autocorrelation function (PACF) plots.

commodities.acf(column = "Spread", ts = "date", p = 12)
commodities.pacf(column = "Spread", ts = "date", p = 5)

We can clearly see the influence of the last two values on Spread, which makes sense. When the curve slightly changes its direction, it will increase/decrease until reaching a new local maximum/minimum. Only the recent values can help the prediction in case of autoregressive periodical model. The local minimums of interest rate spreads are indicators of an economic crisis.

We saw the correlation between the price-per-barrel of Oil and the time. Let’s look at the time series plot of this variable.

commodities["Oil"].plot(ts = "date")

Moving on to the correlation matrix, we can see many events that changed drastically the values of commodities, and we know of a correlation between all of them. From here, we could look at how strong this correlation is, which will help us create a model that properly combines all the variable lags in its predictions.

commodities.corr(columns = ["Gold", "Oil", "Spread", "Vix", "Dol_Eur", "SP500"])

We can see strong correlations between most of the variables. A vector autoregression (VAR) model seems ideal.

Machine Learning

Let’s create the VAR model to predict the value of various commodities.

from verticapy.machine_learning.vertica import VAR

model = VAR(p = 5)
model.fit(
    commodities,
    ts = "date",
    y = ["Gold", "Oil", "Spread", "Vix", "Dol_Eur", "SP500"],
)
model.score()
...
"Dol_Eur"
"SP500"
r2...0.6775587669740350.942839597221071

Our model is excellent. Let’s predict the values these commodities in the near future.

Gold

model.plot(idx = 0, npredictions = 60)

Oil:

model.plot(idx = 1, npredictions = 60)

Spread:

model.plot(idx = 2, npredictions = 60)

Vix:

model.plot(idx = 3, npredictions = 60)

Dol_Eur:

model.plot(idx = 4, npredictions = 60)

The model performs well but may be somewhat unstable. To improve it, we could apply data preparation techniques, such as seasonal decomposition, before building the VAR model.

Conclusion

We’ve solved our problem in a Pandas-like way, all without ever loading data into memory!