| Overall Statistics |
|
Total Trades 91 Average Win 0.41% Average Loss -0.83% Compounding Annual Return -47.600% Drawdown 30.200% Expectancy -0.560 Net Profit -18.133% Sharpe Ratio -1.205 Probabilistic Sharpe Ratio 4.484% Loss Rate 71% Win Rate 29% Profit-Loss Ratio 0.50 Alpha -0.319 Beta 0.272 Annual Standard Deviation 0.28 Annual Variance 0.078 Information Ratio -0.88 Tracking Error 0.308 Treynor Ratio -1.237 Total Fees $290.75 Estimated Strategy Capacity $8700000.00 Lowest Capacity Asset GE R735QTJ8XC9X |
# 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 *
### <summary>
### Framework algorithm that uses the PearsonCorrelationPairsTradingAlphaModel.
### This model extendes BasePairsTradingAlphaModel and uses Pearson correlation
### to rank the pairs trading candidates and use the best candidate to trade.
###
### This modification limits the universe to a specific sector (as per MorningstarSectorCode)
### </summary>
class PearsonCorrelationPairsTradingAlphaModelFrameworkAlgorithm(QCAlgorithm):
'''Framework algorithm that uses the PearsonCorrelationPairsTradingAlphaModel.
This model extendes BasePairsTradingAlphaModel and uses Pearson correlation
to rank the pairs trading candidates and use the best candidate to trade.'''
def Initialize(self):
self.SetStartDate(2022,7,1)
self.sector = self.GetParameter("sector") or "FinancialServices"
self.riskPercent = self.GetParameter("riskPercent", 0.05)
self.topX = int(self.GetParameter("topX", 100))
self.sectors = {
"FinancialServices": MorningstarSectorCode.FinancialServices,
"RealEstate": MorningstarSectorCode.RealEstate,
"Healthcare": MorningstarSectorCode.Healthcare,
"Utilities": MorningstarSectorCode.Utilities,
"Technology": MorningstarSectorCode.Technology,
"BasicMaterials": MorningstarSectorCode.BasicMaterials,
"ConsumerCyclical": MorningstarSectorCode.ConsumerCyclical,
"ConsumerDefensive": MorningstarSectorCode.ConsumerDefensive,
"CommunicationServices": MorningstarSectorCode.CommunicationServices,
"Energy": MorningstarSectorCode.Energy,
"Industrials": MorningstarSectorCode.Industrials}
self.AddUniverseSelection(FineFundamentalUniverseSelectionModel(self.SelectCoarse, self.SelectFine))
self.SetAlpha(PearsonCorrelationPairsTradingAlphaModel(252, Resolution.Daily))
self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel())
self.SetExecution(ImmediateExecutionModel())
# self.SetRiskManagement(TrailingStopRiskManagementModel(self.riskPercent))
# self.AddRiskManagement(MaximumDrawdownPercentPerSecurity(self.riskPercent))
# self.AddRiskManagement(MaximumDrawdownPercentPortfolio(self.riskPercent))
self.SetRiskManagement(NullRiskManagementModel())
def SelectCoarse(self, coarse: List[CoarseFundamental]) -> List[Symbol]:
selected = [c for c in coarse if c.HasFundamentalData]
sorted_by_dollar_volume = sorted(selected, key=lambda c: c.DollarVolume, reverse=True)
return [c.Symbol for c in sorted_by_dollar_volume[:self.topX]] # Return most liquid assets w/ fundamentals
def SelectFine(self, fine):
if self.sector != "all":
filtered_fine = [x.Symbol for x in fine if x.AssetClassification.MorningstarSectorCode == self.sectors[self.sector]]
else:
filtered_fine = [x.Symbol for x in fine]
if len(filtered_fine) < 2:
filtered_fine = []
return filtered_fine # return only assets within one sector (unless sector is 'all', in which case no filter is applied)