| Overall Statistics |
|
Total Orders 1673 Average Win 1.24% Average Loss -0.54% Compounding Annual Return -0.925% Drawdown 15.000% Expectancy 0.011 Start Equity 100000 End Equity 95455.69 Net Profit -4.544% Sharpe Ratio -0.66 Sortino Ratio -0.761 Probabilistic Sharpe Ratio 0.198% Loss Rate 69% Win Rate 31% Profit-Loss Ratio 2.30 Alpha -0.041 Beta 0.01 Annual Standard Deviation 0.062 Annual Variance 0.004 Information Ratio -0.734 Tracking Error 0.153 Treynor Ratio -4.13 Total Fees $0.00 Estimated Strategy Capacity $0 Lowest Capacity Asset BCOUSD 8I Portfolio Turnover 53.85% Drawdown Recovery 287 |
#region imports
from AlgorithmImports import *
from sklearn.linear_model import LinearRegression
#endregion
class TradeWtiBrentSpreadAlgorithm(QCAlgorithm):
def initialize(self):
self.set_start_date(self.end_date - timedelta(5*365))
self.set_cash(100000)
# import the spot price data
self._wti = self.add_cfd("WTICOUSD", Resolution.DAILY, Market.OANDA)
self._b = self.add_cfd("BCOUSD", Resolution.DAILY, Market.OANDA)
# Recalibrate model every month
self.train(self.date_rules.month_start(), self.time_rules.midnight, self._my_training_method)
# create the moving average indicator of the pread = WTI price - BRENT price
self._spread_sma = SimpleMovingAverage(20)
wti_hist, b_hist = self._get_history()
spread = wti_hist - b_hist
for index, value in spread.iloc[-20:].items():
self._spread_sma.update(index, value)
# linear regression to decide the fair value
self._regr = LinearRegression()
self._regr.fit(wti_hist.values.reshape(-1, 1), b_hist.values.reshape(-1, 1))
# Add the spread plot and mark the long/short spread point
spread_plot = Chart("Spread Plot")
spread_plot.add_series(Series("Spread", SeriesType.LINE, 0))
spread_plot.add_series(Series("Long Spread Trade", SeriesType.SCATTER, 0))
spread_plot.add_series(Series("Short Spread Trade", SeriesType.SCATTER, 0))
self.add_chart(spread_plot)
def _get_history(self):
hist = self.history([self._wti, self._b], 252, Resolution.DAILY).unstack(level=0)['close'].ffill().dropna()
return hist[self._wti.symbol], hist[self._b.symbol]
def _my_training_method(self):
wti_hist, b_hist = self._get_history()
# linear regression to decide the fair value
self._regr.fit(wti_hist.values.reshape(-1, 1), b_hist.values.reshape(-1, 1))
def on_data(self, data):
if not (data.contains_key(self._wti) and data.contains_key(self._b)):
return
spread = self._wti.price - self._b.price
self.plot("Spread Plot", "Spread", spread)
self._spread_sma.update(self.time, spread)
fair_value = self._wti.price - self._regr.predict(np.array([self._wti.price]).reshape(1, -1))[0]
if spread > self._spread_sma.current.value and not (self._wti.holdings.is_short and self._b.holdings.is_long):
self.set_holdings(self._wti, -0.5)
self.set_holdings(self._b, 0.5)
self.plot("Spread Plot", "Long Spread Trade", spread)
elif spread < self._spread_sma.current.value and not (self._wti.holdings.is_long and self._b.holdings.is_short):
self.set_holdings(self._wti, 0.5)
self.set_holdings(self._b, -0.5)
self.plot("Spread Plot", "Short Spread Trade", spread)
if self._wti.holdings.is_short and self._b.holdings.is_long and spread < fair_value:
self.liquidate()
if self._wti.holdings.is_long and self._b.holdings.is_short and spread > fair_value:
self.liquidate()