Forecasting Crude Oil Prices
Log in to collectAcademic paper
Forecasting Crude Oil Prices: Does Global Financial Uncertainty Matter?
Yong Ma; shuaibing li; Mingtao Zhou
- Hunan University of Finance and Economics
- ?Hunan University - School of Finance and Statistics
- ?Hunan University, School of Finance and Statistics
- Hunan University
Strategy in a nutshell
Invest in crude oil derivatives (futures or spot). Use a univariate regression with GFU as predictor to forecast next-month oil returns. Buy or short monthly based on GFU signals. Portfolio: single position, monthly rebalancing. Suitable for investors with risk aversion coefficient of 3.
Economic rationale
GFU is a robust alternative data predictor for crude oil returns. It improves forecasting accuracy, remains statistically and economically significant, and enriches existing literature on commodity market timing strategies.
Backtest performance
Annualised return4.65%
Volatility19.38%
Beta-0.206
Sharpe ratio0.24
Win rate31%
Full Python code
from AlgorithmImports import *
import data_tools
import statsmodels.api as sm
# endregion
class ForecastingCrudeOilPrices(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2000, 1, 1)
self.SetCash(100000)
leverage:int = 3
self.oil:Symbol = self.AddData(data_tools.QuantpediaFutures, 'CME_CL1', Resolution.Daily).Symbol
self.Securities[self.oil].SetLeverage(leverage)
self.gfu:Symbol = self.AddData(data_tools.GFU, 'GFU', Resolution.Daily).Symbol
# self.test_size:float = 0.2
self.min_period:int = 12
self.price_storage:Dict[Symbol, List] = {}
for symbol in [self.oil, self.gfu]:
self.price_storage[symbol] = []
def OnData(self, data: Slice) -> None:
rebalance = False
# store daily price
if self.gfu in data and data[self.gfu]:
self.price_storage[self.gfu].append(data[self.gfu].Value)
self.price_storage[self.oil].append(self.Securities[self.oil].Price)
rebalance = True
# rebalance once new GFU data arrived
if rebalance:
last_update_date = [c.get_last_update_date() for c in [data_tools.QuantpediaFutures, data_tools.GFU]]
if all(self.Securities[symbol].GetLastData() and last_update_date[i] > self.Time.date() for i, symbol in enumerate([self.oil, self.gfu])):
if all(len(self.price_storage[symbol]) >= self.min_period for symbol in [self.oil, self.gfu]):
oil_prices:np.ndarray = np.array(self.price_storage[self.oil])
x:np.ndarray = np.array(self.price_storage[self.gfu])[1:]
y:np.ndarray = np.log(oil_prices[1:] / oil_prices[:-1]) # oil monthly log returns
# run regression
model = data_tools.multiple_linear_regression(x[:-1], y[1:])
predicted_oil_return:float = model.predict([1, x[-1]])[0]
# test_size:int = int(len(self.price_storage[self.oil]) * self.test_size)
# model = data_tools.multiple_linear_regression(x[:-1][:-test_size], y[1:][:-test_size])
# predicted_oil_return:float = model.predict(sm.add_constant(x[-test_size:]))[-1] if test_size > 1 else model_.predict([1, x[-test_size:]])[-1][0]
# trade based on prediction
if predicted_oil_return > 0:
self.SetHoldings(self.oil, 1)
else:
# self.Liquidate(self.oil)
self.SetHoldings(self.oil, -1)
else:
self.Liquidate()
return