Skip to content
All library documents

Trading Brent–WTI Spread Signals with Intrinio Economic Data

Article Strategy library · Author: QuantConnect

Summary

This example combines daily Intrinio observations for West Texas Intermediate and Brent crude prices with two oil fund positions. It calculates the Brent-minus-WTI spread and takes opposing positions in the funds: a positive spread leads to a long Brent fund position and a short WTI fund position, while a negative spread reverses those directions. Position targets are set to one quarter of the portfolio for each fund, and leverage is configured for both securities.

The sample also shows how to configure Intrinio credentials and limit historical data requests, but it gives no backtest results or evidence that the spread predicts returns. Its logic is a simple sign-based allocation rule; it does not define thresholds, transaction cost treatment, or risk controls beyond target weights. The data check allows processing when either series is present, although calculating the spread requires both values, so missing observations may cause a problem. The listed EMA is not used in the trading decisions.

Key ideas

  • The example compares daily Brent and WTI economic data to form a price spread.
  • It takes opposing positions in Brent and WTI funds based on whether the spread is positive or negative.
  • Each fund receives a target allocation of one quarter of the portfolio, with leverage configured separately.
  • The sample provides no performance evidence and does not use its calculated EMA in the entry logic.
  • Spread calculation requires both price series, so checking for either one alone may not be sufficient.

Tags

Full text
# BasicTemplateIntrinioEconomicData


# BasicTemplateIntrinioEconomicData









## Source (Apache-2.0)

```python
# QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
# Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from AlgorithmImports import *

from QuantConnect.Data.Custom.Intrinio import *

class BasicTemplateIntrinioEconomicData(QCAlgorithm):

    def initialize(self):
        '''initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.'''

        self.set_start_date(2010, 1, 1)  #Set Start Date
        self.set_end_date(2013, 12, 31)  #Set End Date
        self.set_cash(100000)           #Set Strategy Cash

        # Set your Intrinio user and password.
        IntrinioConfig.set_user_and_password("intrinio-username", "intrinio-password")
        # The Intrinio user and password can be also defined in the config.json file for local backtest.

        # Set Intrinio config to make 1 call each minute, default is 1 call each 5 seconds.
        #(1 call each minute is the free account limit for historical_data endpoint)
        IntrinioConfig.set_time_interval_between_calls(timedelta(minutes = 1))

        # United States Oil Fund LP
        self.uso = self.add_equity("USO", Resolution.DAILY).symbol
        self.securities[self.uso].set_leverage(2)
        # United States Brent Oil Fund LP
        self.bno = self.add_equity("BNO", Resolution.DAILY).symbol
        self.securities[self.bno].set_leverage(2)

        self.add_data(IntrinioEconomicData, "$DCOILWTICO", Resolution.DAILY)
        self.add_data(IntrinioEconomicData, "$DCOILBRENTEU", Resolution.DAILY)

        self.ema_wti = self.ema("$DCOILWTICO", 10)


    def on_data(self, slice):
        '''on_data event is the primary entry point for your algorithm. Each new data point will be pumped in here.
        Arguments:
            data: Slice object keyed by symbol containing the stock data
        '''
        if (slice.contains_key("$DCOILBRENTEU") or slice.contains_key("$DCOILWTICO")):
            spread = slice["$DCOILBRENTEU"].value - slice["$DCOILWTICO"].value
        else:
            return

        if ((spread > 0 and not self.portfolio[self.bno].is_long) or
            (spread < 0 and not self.portfolio[self.uso].is_short)):
            sign = math.copysign(1, spread)
            self.set_holdings(self.bno, 0.25 * sign)
            self.set_holdings(self.uso, -0.25 * sign)


```

Shown in full with attribution under the source's licence. Licence: Apache-2.0

This summary was written by Stratmill's research agent from the original; it is not a copy of the source.