Overall Statistics |
Total Orders 62 Average Win 1.46% Average Loss -1.67% Compounding Annual Return -1.613% Drawdown 7.000% Expectancy 0.004 Start Equity 100000 End Equity 98786.38 Net Profit -1.214% Sharpe Ratio -0.535 Sortino Ratio -0.657 Probabilistic Sharpe Ratio 11.741% Loss Rate 46% Win Rate 54% Profit-Loss Ratio 0.87 Alpha -0.039 Beta 0.033 Annual Standard Deviation 0.07 Annual Variance 0.005 Information Ratio -0.483 Tracking Error 0.149 Treynor Ratio -1.127 Total Fees $0.00 Estimated Strategy Capacity $0 Lowest Capacity Asset XAGUSD 8I Portfolio Turnover 19.83% |
from AlgorithmImports import * from QuantConnect.DataSource import * class SMAPairsTrading(QCAlgorithm): def initialize(self) -> None: self.set_start_date(2018, 7, 1) self.set_end_date(2019, 3, 31) self.set_cash(100000) # Request gold and sliver spot CFDs for trading their spread difference, assuming their spread series is cointegrated self.add_cfd('XAUUSD', Resolution.HOUR) self.add_cfd('XAGUSD', Resolution.HOUR) # Use 500-step mean and SD indicator on determine the spread relative difference for trading signal generation self.pair = [ ] self.spread_mean = SimpleMovingAverage(500) self.spread_std = StandardDeviation(500) def on_data(self, slice: Slice) -> None: # Update the indicator with updated spread difference, such that the an updated cointegration threshold is calculated for trade inception spread = self.pair[1].price - self.pair[0].price self.spread_mean.update(self.time, spread) self.spread_std.update(self.time, spread) spread_mean = self.spread_mean.current.value upperthreshold = spread_mean + self.spread_std.current.value lowerthreshold = spread_mean - self.spread_std.current.value # If the spread is higher than upper threshold, bet theie spread series will revert to mean if spread > upperthreshold: self.set_holdings(self.pair[0].symbol, 1) self.set_holdings(self.pair[1].symbol, -1) elif spread < lowerthreshold: self.set_holdings(self.pair[0].symbol, -1) self.set_holdings(self.pair[1].symbol, 1) # Close positions if mean reverted elif (self.portfolio[self.pair[0].symbol].quantity > 0 and spread < spread_mean)\ or (self.portfolio[self.pair[0].symbol].quantity < 0 and spread > spread_mean): self.liquidate() def on_securities_changed(self, changes: SecurityChanges) -> None: self.pair = [x for x in changes.added_securities] #1. Call for 500 bars of history data for each symbol in the pair and save to the variable history history = self.history([x.symbol for x in self.pair], 500) #2. Unstack the Pandas data frame to reduce it to the history close price history = history.close.unstack(level=0) #3. Iterate through the history tuple and update the mean and standard deviation with historical data for tuple in history.itertuples(): self.spread_mean.update(tuple[0], tuple[2]-tuple[1]) self.spread_std.update(tuple[0], tuple[2]-tuple[1])