Asset Classes
Crypto Futures
Trades
To get historical trade data, call the History<TradeBar>
method with a security's Symbol
.
To get historical trade data, call the history
method with the TradeBar
type and a security's Symbol
.
This method returns a DataFrame with columns for the open, high, low, close, and volume.
public class CryptoFutureTradeBarHistoryAlgorithm : QCAlgorithm { public override void Initialize() { SetStartDate(2024, 12, 19); // Get the Symbol of a security. var symbol = AddCryptoFuture("BTCUSD").Symbol; // Get the 5 trailing daily TradeBar objects of the security. var history = History<TradeBar>(symbol, 5, Resolution.Daily); // Iterate through each TradeBar and calculate its dollar volume. foreach (var bar in history) { var t = bar.EndTime; var dollarVolume = bar.Close * bar.Volume; } } }
class CryptoFutureTradeBarHistoryAlgorithm(QCAlgorithm): def initialize(self) -> None: self.set_start_date(2024, 12, 19) # Get the Symbol of a security. symbol = self.add_crypto_future('BTCUSD').symbol # Get the 5 trailing daily TradeBar objects of the security in DataFrame format. history = self.history(TradeBar, symbol, 5, Resolution.DAILY)
close | high | low | open | volume | ||
---|---|---|---|---|---|---|
symbol | time | |||||
BTCUSD | 2024-12-15 | 101383.8 | 102683.9 | 100563.7 | 101403.8 | 16666498.0 |
2024-12-16 | 104500.0 | 105323.5 | 101209.8 | 101383.9 | 26232316.0 | |
2024-12-17 | 106120.0 | 107872.1 | 103320.0 | 104500.0 | 44897036.0 | |
2024-12-18 | 106171.2 | 108496.9 | 105369.3 | 106120.0 | 41849071.0 | |
2024-12-19 | 100163.2 | 106550.2 | 99911.0 | 106171.2 | 65325574.0 |
# Calculate the daily returns. daily_returns = history.close.pct_change().iloc[1:]
symbol time BTCUSD 2024-12-16 0.030737 2024-12-17 0.015502 2024-12-18 0.000482 2024-12-19 -0.056588 Name: close, dtype: float64
If you intend to use the data in the DataFrame to create TradeBar
objects, request that the history request returns the data type you need.
Otherwise, LEAN consumes unnecessary computational resources populating the DataFrame.
To get a list of TradeBar
objects instead of a DataFrame, call the history[TradeBar]
method.
# Get the 5 trailing daily TradeBar objects of the security in TradeBar format. history = self.history[TradeBar](symbol, 5, Resolution.DAILY) # Iterate through the TradeBar objects and access their volumes. for trade_bar in history: t = trade_bar.end_time volume = trade_bar.volume
Quotes
To get historical quote data, call the History<QuoteBar>
method with a security's Symbol
.
To get historical quote data, call the history
method with the QuoteBar
type and a security's Symbol
.
This method returns a DataFrame with columns for the open, high, low, close, and size of the bid and ask quotes.
The columns that don't start with "bid" or "ask" are the mean of the quote prices on both sides of the market.
public class CryptoFutureQuoteBarHistoryAlgorithm : QCAlgorithm { public override void Initialize() { SetStartDate(2024, 12, 19); // Get the Symbol of a security. var symbol = AddCryptoFuture("BTCUSD").Symbol; // Get the 5 trailing minute QuoteBar objects of the security. var history = History<QuoteBar>(symbol, 5, Resolution.Minute); // Iterate through the QuoteBar objects and calculate the spread. foreach (var bar in history) { var t = bar.EndTime; var spread = bar.Ask.Close - bar.Bid.Close; } } }
class CryptoFutureQuoteBarHistoryAlgorithm(QCAlgorithm): def initialize(self) -> None: self.set_start_date(2024, 12, 19) # Get the Symbol of a security. symbol = self.add_crypto_future('BTCUSD').symbol # Get the 5 trailing minute QuoteBar objects of the security in DataFrame format. history = self.history(QuoteBar, symbol, 5, Resolution.MINUTE)
askclose | askhigh | asklow | askopen | asksize | bidclose | bidhigh | bidlow | bidopen | bidsize | close | high | low | open | ||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
symbol | time | ||||||||||||||
BTCUSD | 2024-12-19 04:56:00 | 100744.2 | 100753.9 | 100727.5 | 100753.9 | 6420.0 | 100744.1 | 100753.8 | 100727.1 | 100753.8 | 4237.0 | 100744.15 | 100753.85 | 100727.30 | 100753.85 |
2024-12-19 04:57:00 | 100727.3 | 100744.2 | 100727.3 | 100744.2 | 5674.0 | 100727.2 | 100744.1 | 100727.2 | 100744.1 | 742.0 | 100727.25 | 100744.15 | 100727.25 | 100744.15 | |
2024-12-19 04:58:00 | 100698.5 | 100727.3 | 100653.0 | 100727.3 | 6707.0 | 100698.4 | 100727.2 | 100652.8 | 100727.2 | 3719.0 | 100698.45 | 100727.25 | 100652.90 | 100727.25 | |
2024-12-19 04:59:00 | 100606.1 | 100698.5 | 100606.1 | 100698.5 | 1.0 | 100606.0 | 100698.4 | 100606.0 | 100698.4 | 5076.0 | 100606.05 | 100698.45 | 100606.05 | 100698.45 | |
2024-12-19 05:00:00 | 100644.1 | 100655.4 | 100606.1 | 100606.1 | 6005.0 | 100644.0 | 100655.3 | 100606.0 | 100606.0 | 611.0 | 100644.05 | 100655.35 | 100606.05 | 100606.05 |
# Calculate the spread at each minute. spread = history.askclose - history.bidclose
symbol time BTCUSD 2024-12-19 04:56:00 0.1 2024-12-19 04:57:00 0.1 2024-12-19 04:58:00 0.1 2024-12-19 04:59:00 0.1 2024-12-19 05:00:00 0.1 dtype: float64
If you intend to use the data in the DataFrame to create QuoteBar
objects, request that the history request returns the data type you need.
Otherwise, LEAN consumes unnecessary computational resources populating the DataFrame.
To get a list of QuoteBar
objects instead of a DataFrame, call the history[QuoteBar]
method.
# Get the 5 trailing minute QuoteBar objects of the security in QuoteBar format. history = self.history[QuoteBar](symbol, 5, Resolution.MINUTE) # Iterate through each QuoteBar and calculate the dollar volume on the bid. for quote_bar in history: t = quote_bar.end_time bid_dollar_volume = quote_bar.last_bid_size * quote_bar.bid.close
Ticks
To get historical tick data, call the History<Tick>
method with a security's Symbol
and Resolution.Tick
.
To get historical tick data, call the history
method with a security's Symbol
and Resolution.TICK
.
This method returns a DataFrame that contains data on bids, asks, and last trade prices.
public class CryptoFutureTickHistoryAlgorithm : QCAlgorithm { public override void Initialize() { SetStartDate(2024, 12, 19); // Get the Symbol of a security. var symbol = AddCryptoFuture("BTCUSD").Symbol; // Get the trailing 2 days of ticks for the security. var history = History<Tick>(symbol, TimeSpan.FromDays(2), Resolution.Tick); // Select the ticks that represent trades, excluding the quote ticks. var trades = history.Where(tick => tick.TickType == TickType.Trade); } }
class CryptoFutureTickHistoryAlgorithm(QCAlgorithm): def initialize(self) -> None: self.set_start_date(2024, 12, 19) # Get the Symbol of a security. symbol = self.add_crypto_future('BTCUSD').symbol # Get the trailing 2 days of ticks for the security in DataFrame format. history = self.history(symbol, timedelta(2), Resolution.TICK)
askprice | asksize | bidprice | bidsize | lastprice | quantity | ||
---|---|---|---|---|---|---|---|
symbol | time | ||||||
BTCUSD | 2024-12-17 05:00:00.132868 | 106537.1 | 12342.0 | 106537.0 | 35.0 | 106537.05 | 0.0 |
2024-12-17 05:00:00.145098 | 106537.1 | 12353.0 | 106537.0 | 35.0 | 106537.05 | 0.0 | |
2024-12-17 05:00:00.424485 | 106537.1 | 12353.0 | 106537.0 | 355.0 | 106537.05 | 0.0 | |
2024-12-17 05:00:00.427716 | 106537.1 | 12353.0 | 106537.0 | 354.0 | 106537.05 | 0.0 | |
2024-12-17 05:00:00.431177 | 106537.1 | 12353.0 | 106537.0 | 355.0 | 106537.05 | 0.0 |
# Select the rows in the DataFrame that represent trades. Drop the bid/ask columns since they are NaN. trade_ticks = history[history.quantity > 0].dropna(axis=1)
lastprice | quantity | ||
---|---|---|---|
symbol | time | ||
BTCUSD | 2024-12-17 05:00:01.008 | 106537.1 | 2.0 |
2024-12-17 05:00:02.729 | 106537.0 | 2.0 | |
2024-12-17 05:00:02.971 | 106537.0 | 5.0 | |
2024-12-17 05:00:05.977 | 106537.0 | 4.0 | |
2024-12-17 05:00:14.072 | 106537.1 | 56.0 |
If you intend to use the data in the DataFrame to create Tick
objects, request that the history request returns the data type you need.
Otherwise, LEAN consumes unnecessary computational resources populating the DataFrame.
To get a list of Tick
objects instead of a DataFrame, call the history[Tick]
method.
# Get the trailing 2 days of ticks for the security in Tick format. history = self.history[Tick](symbol, timedelta(2), Resolution.TICK) # Iterate through each quote tick and calculate the quote size. for tick in history: if tick.tick_type == TickType.Quote: t = tick.end_time size = max(tick.bid_size, tick.ask_size)
Ticks are a sparse dataset, so request ticks over a trailing period of time or between start and end times.
Slices
To get historical Slice data, call the History
history
method without passing any Symbol
objects.
This method returns Slice
objects, which contain data points from all the datasets in your algorithm.
If you omit the resolution
argument, it uses the resolution that you set for each security and dataset when you created the subscriptions.
public class SliceHistoryAlgorithm : QCAlgorithm { public override void Initialize() { SetStartDate(2024, 12, 1); // Add some securities and datasets. AddCryptoFuture("BTCUSD"); // Get the historical Slice objects over the last 5 days for all the subcriptions in your algorithm. var history = History(5, Resolution.Daily); // Iterate through each historical Slice. foreach (var slice in history) { // Iterate through each TradeBar in this Slice. foreach (var kvp in slice.Bars) { var symbol = kvp.Key; var bar = kvp.Value; } } } }
class SliceHistoryAlgorithm(QCAlgorithm): def initialize(self) -> None: self.set_start_date(2024, 12, 1) # Add some securities and datasets. self.add_crypto_future('BTCUSD') # Get the historical Slice objects over the last 5 days for all the subcriptions in your algorithm. history = self.history(5, Resolution.DAILY) # Iterate through each historical Slice. for slice_ in history: # Iterate through each TradeBar in this Slice. for symbol, trade_bar in slice_.bars.items(): close = trade_bar.close
Margin Interest Rates
To get historical margin interest rate data, call the History<MarginInterestRate>
method with a security's Symbol
.
To get historical margin interest rate data, call the history
method with the MarginInterestRate
type and a security's Symbol
.
This method returns a DataFrame with a single column for the interest rate.
public class CryptoFutureMarginInterestRateHistoryAlgorithm : QCAlgorithm { public override void Initialize() { SetStartDate(2024, 12, 19); // Get the Symbol of a security. var symbol = AddCryptoFuture("BTCUSD").Symbol; // Get the MarginInterestRate objects of the security over the last 2 trading days. var history = History<MarginInterestRate>(symbol, 2, Resolution.Daily); // Iterate through each MarginInterestRate object and get its value. foreach (var dataPoint in history) { var t = dataPoint.EndTime; var interestRate = dataPoint.InterestRate; } } }
class CryptoFutureMarginInterestRateHistoryAlgorithmHistoryAlgorithm(QCAlgorithm): def initialize(self) -> None: self.set_start_date(2024, 12, 19) # Get the Symbol of a security. symbol = self.add_crypto_future('BTCUSD').symbol # Get the MarginInterestRate data of the security over the last 2 trading days in DataFrame format. history = self.history(MarginInterestRate, symbol, 2, Resolution.DAILY)
interestrate | ||
---|---|---|
symbol | time | |
BTCUSD | 2024-12-17 08:00:00 | 0.0001 |
2024-12-17 16:00:00 | 0.0001 | |
2024-12-18 00:00:00 | 0.0001 | |
2024-12-18 08:00:00 | 0.0001 | |
2024-12-18 16:00:00 | 0.0001 | |
2024-12-19 00:00:00 | 0.0001 |
# Calculate the change in interest rates. delta = history.interestrate.diff()[1:]
symbol time BTCUSD 2024-12-17 16:00:00 0.0 2024-12-18 00:00:00 0.0 2024-12-18 08:00:00 0.0 2024-12-18 16:00:00 0.0 2024-12-19 00:00:00 0.0 Name: interestrate, dtype: float64
If you intend to use the data in the DataFrame to create MarginInterestRate
objects, request that the history request returns the data type you need.
Otherwise, LEAN consumes unnecessary computational resources populating the DataFrame.
To get a list of MarginInterestRate
objects instead of a DataFrame, call the history[MarginInterestRate]
method.
# Get the MarginInterestRate data of the security over the last 2 trading days in MarginInterestRate format. history = self.history[MarginInterestRate](symbol, 2, Resolution.DAILY) # Iterate through the MarginInterestRate objects and access their values for margin_interest_rate in history: t = margin_interest_rate.end_time interest_rate = margin_interest_rate.interest_rate
Indicators
To get historical indicator values, call the IndicatorHistory
indicator_history
method with an indicator and the security's Symbol
.
public class CryptoFutureIndicatorHistoryAlgorithm : QCAlgorithm { public override void Initialize() { SetStartDate(2024, 12, 19); // Get the Symbol of a security. var symbol = AddCryptoFuture("BTCUSD").Symbol; // Get the 21-day SMA values of the security for the last 5 trading days. var history = IndicatorHistory(new SimpleMovingAverage(21), symbol, 5, Resolution.Daily); // Get the maximum of the SMA values. var maxSMA = history.Max(indicatorDataPoint => indicatorDataPoint.Current.Value); } }
class CryptoFutureIndicatorHistoryAlgorithm(QCAlgorithm): def initialize(self) -> None: self.set_start_date(2024, 12, 19) # Get the Symbol of a security. symbol = self.add_crypto_future('BTCUSD').symbol # Get the 21-day SMA values of the security for the last 5 trading days. history = self.indicator_history(SimpleMovingAverage(21), symbol, 5, Resolution.DAILY)
To organize the data into a DataFrame, use the data_frame
property of the result.
# Organize the historical indicator data into a DataFrame to enable pandas wrangling. history_df = history.data_frame
current | rollingsum | |
---|---|---|
2024-12-15 | 97759.090476 | 2052940.9 |
2024-12-16 | 98065.342857 | 2059372.2 |
2024-12-17 | 98689.038095 | 2072469.8 |
2024-12-18 | 99363.738095 | 2086638.5 |
2024-12-19 | 99563.576190 | 2090835.1 |
# Get the maximum of the SMA values. sma_max = history_df.current.max()
The IndicatorHistory
indicator_history
method resets your indicator, makes a history request, and updates the indicator with the historical data.
Just like with regular history requests, the IndicatorHistory
indicator_history
method supports time periods based on a trailing number of bars, a trailing period of time, or a defined period of time.
If you don't provide a resolution
argument, it defaults to match the resolution of the security subscription.
To make the IndicatorHistory
indicator_history
method update the indicator with an alternative price field instead of the close (or mid-price) of each bar, pass a selector
argument.
// Get the historical values of an indicator over the last 30 days, applying the indicator to the security's volume. var history = IndicatorHistory(indicator, symbol, TimeSpan.FromDays(30), selector: Field.Volume);
# Get the historical values of an indicator over the last 30 days, applying the indicator to the security's volume. history = self.indicator_history(indicator, symbol, timedelta(30), selector=Field.VOLUME)
Some indicators require the prices of two securities to compute their value (for example, Beta).
In this case, pass a list of the Symbol
objects to the method.
public class CryptoFutureMultiAssetIndicatorHistoryAlgorithm : QCAlgorithm { public override void Initialize() { SetStartDate(2024, 12, 19); // Add the target and reference securities. var targetSymbol = AddCryptoFuture("DOGEUSD").Symbol; var referenceSymbol = AddCryptoFuture("BTCUSD").Symbol; // Create a 21-period Beta indicator. var beta = new Beta("", targetSymbol, referenceSymbol, 21); // Get the historical values of the indicator over the last 10 trading days. var history = IndicatorHistory(beta, new[] {targetSymbol, referenceSymbol}, 10, Resolution.Daily); // Get the average Beta value. var avgBeta = history.Average(indicatorDataPoint => indicatorDataPoint.Current.Value); } }
class CryptoFutureMultiAssetIndicatorHistoryAlgorithm(QCAlgorithm): def initialize(self) -> None: self.set_start_date(2024, 12, 19) # Add the target and reference securities. target_symbol = self.add_crypto_future('DOGEUSD').symbol reference_symbol = self.add_crypto_future('BTCUSD').symbol # Create a 21-period Beta indicator. beta = Beta("", target_symbol, reference_symbol, 21) # Get the historical values of the indicator over the last 10 trading days. history = self.indicator_history(beta, [target_symbol, reference_symbol], 10, Resolution.DAILY) # Get the average Beta value. beta_avg = history.data_frame.mean()
If you already have a list of Slice objects, you can pass them to the IndicatorHistory
indicator_history
method to avoid the internal history request.
var slices = History(new[] {symbol}, 30, Resolution.Daily); var history = IndicatorHistory(indicator, slices);
Examples
The following examples demonstrate common practices for trading cryptocurrency futures with historical data.
Example 1: Spot-Future Arbitrage
The example below uses linear regression with historical Spot and Future BTCUSDT data to obtain the cointegrating vector between them. We measure the spread between the two securities and trade mean reversal upon their spread divergence.
using MathNet.Numerics.LinearRegression; using Accord.Math; public class CointegrationVectorRegressionAlgorithm : QCAlgorithm { private Symbol _spot, _future; private decimal[] _cointegrationVector = new[] { 0m, 0m }; private decimal _residualMean = 0m; private decimal _residualStd = 1m; private decimal _entryThreshold = 2m; public override void Initialize() { SetStartDate(2024, 1, 1); SetEndDate(2025, 1, 1); SetAccountCurrency("USDT", 100000); SetCash("BTC", 2); SetSecurityInitializer(new BrokerageModelSecurityInitializer(BrokerageModel, new FuncSecuritySeeder(GetLastKnownPrices))); // Request BTCUSDT Crypto and Crypto Future data to form the cointegrating vectors and trade. _spot = AddCrypto("BTCUSDT", market: Market.Bybit).Symbol; _future = AddCryptoFuture("BTCUSDT", market: Market.Bybit).Symbol; // Daily recalibration on the cointegrating vectors. Schedule.On( DateRules.EveryDay(_future), TimeRules.At(0, 1), Recalibrate ); } public override void OnData(Slice slice) { if (slice.Bars.TryGetValue(_future, out var y) && slice.Bars.TryGetValue(_spot, out var x1)) { // Calculate the spread based on the cointegration vector. var spread = CalculateSpread(y.Close, x1.Close, _cointegrationVector); var normalizedSpread = (spread - _residualMean) / _residualStd; // If the spread is too high, short the dependent and long the independent variables based on the weightings of the cointegrating vectors. // Else, and vice versa. var totalWeights = Math.Abs(_cointegrationVector[1]) + 1m; if (normalizedSpread > _entryThreshold && !Portfolio[_future].IsShort) { SetHoldings(_future, -1m / totalWeights); SetHoldings(_spot, _cointegrationVector[1] / totalWeights); } else if (normalizedSpread < -_entryThreshold && !Portfolio[_future].IsLong) { SetHoldings(_future, 1m / totalWeights); SetHoldings(_spot, -_cointegrationVector[1] / totalWeights); } // Exit if spread is converged. if ((Portfolio[_future].IsShort && normalizedSpread < 0m) || (Portfolio[_future].IsLong && normalizedSpread > 0m)) { Liquidate(); } } } private void Recalibrate() { // Calculate the cointegration vector from historical data. var history = History<TradeBar>(new[] { _future, _spot }, 252, Resolution.Daily) .Where(x => x.ContainsKey(_future) && x.ContainsKey(_spot)) .ToList(); _cointegrationVector = CalculateCointegrationVector(history); var residual = history.Select(x => CalculateSpread(x[_future].Close, x[_spot].Close, _cointegrationVector)).ToArray(); _residualMean = residual.Average(); _residualStd = Convert.ToDecimal(Math.Sqrt(residual.Sum(x => Math.Pow((double)(x - _residualMean), 2)) / residual.Length)); } private decimal[] CalculateCointegrationVector(IEnumerable<DataDictionary<TradeBar>> history) { // Use log price to eliminate the compounding effect. var y = history.Select(x => Math.Log((double)x[_future].Close)).ToArray(); var x1 = history.Select(x => Math.Log((double)x[_spot].Close)).ToArray(); // Create a matrix for the regression analysis. var n = new[] { y.Length, x1.Length }.Min(); var designMatrix = new double[n][]; for (int i = 0; i < n; i++) { designMatrix[i] = new[] { x1[i] }; } try { // Perform regression using MathNet.Numerics var coefficients = MultipleRegression.QR(designMatrix, y.TakeLast(n).ToArray(), intercept: true); // The coefficients array will contain the intercept and the coefficients for each independent variable. return new[] { (decimal)coefficients[0], (decimal)coefficients[1] }; } catch { return _cointegrationVector; } } private decimal CalculateSpread(decimal y, decimal x1, decimal[] cointegrationVector) { // Using the cointegration vector to calculate the spread. return LogPrice(y) - (cointegrationVector[0] + LogPrice(x1) * cointegrationVector[1]); } private decimal LogPrice(decimal price) { return Convert.ToDecimal(Math.Log((double)price)); } }
from sklearn.linear_model import LinearRegression class CointegrationVectorRegressionAlgorithm(QCAlgorithm): # Threshold of spread divergence to enter position. entry_threshold = 2 def initialize(self) -> None: self.set_start_date(2024, 1, 1) self.set_end_date(2025, 1, 1) self.set_account_currency("USDT", 100000) self.set_cash("BTC", 2) # Request BTCUSDT Crypto and Crypto Future data to form the cointegrating vectors and trade. self._future = self.add_crypto_future("BTCUSDT", market=Market.BYBIT).symbol self._spot = self.add_crypto("BTCUSDT", market=Market.BYBIT).symbol # Initialize cointegration vector. self.cointegration_vector = np.array([0.0, 0.0]) self.residual_mean = 0 self.residual_std = 1 # Daily recalibration on the cointegrating vectors. self.schedule.on( self.date_rules.every_day(self._future), self.time_rules.at(0, 1), self.recalibrate ) def on_data(self, slice: Slice) -> None: y = slice.bars.get(self._future) x1 = slice.bars.get(self._spot) if y and x1: # Calculate the spread based on the cointegration vector. spread = self.calculate_spread(y.close, x1.close, self.cointegration_vector) normalized_spread = (spread - self.residual_mean) / self.residual_std # If the spread is too high, short the dependent and long the independent variables based on the weightings of the cointegrating vectors. # Else, vice versa. total_weights = abs(self.cointegration_vector[1]) + 1 if normalized_spread > self.entry_threshold and not self.portfolio[self._future].is_short: self.set_holdings(self._future, -0.5 / total_weights) self.set_holdings(self._spot, 0.5 * self.cointegration_vector[1] / total_weights) elif normalized_spread < -self.entry_threshold and not self.portfolio[self._future].is_long: self.set_holdings(self._future, 0.5 / total_weights) self.set_holdings(self._spot, -0.5 * self.cointegration_vector[1] / total_weights) # Exit if spread is converged. if (self.portfolio[self._future].is_short and normalized_spread < 0) or (self.portfolio[self._future].is_long and normalized_spread > 0): self.liquidate() def recalibrate(self) -> None: # Calculate the cointegration vector from historical data. log_price = np.log(self.history([self._future, self._spot], 252, Resolution.DAILY).unstack(0).close.dropna()) self.cointegration_vector = self.calculate_cointegrating_vector(log_price) residual = log_price.apply(lambda x: self.calculate_spread(x[self._future], x[self._spot], self.cointegration_vector), axis=1) self.residual_mean, self.residual_std = np.mean(residual), np.std(residual, ddof=1) def calculate_cointegrating_vector(self, log_price: pd.DataFrame) -> np.array: try: # Perform regression. lr = LinearRegression().fit(log_price[[self._spot]], log_price[self._future]) # The coefficients array will contain the coefficients for each independent variable. return np.array([lr.intercept_, lr.coef_[0]]) except: return self.cointegration_vector def calculate_spread(self, y: float, x1: float, cointegration_vector: np.array) -> float: # Using the cointegration vector to calculate the spread. return np.log(y) - (cointegration_vector[0] + np.log(x1) * cointegration_vector[1])