Overall Statistics |
Total Trades 1250 Average Win 0.00% Average Loss 0.00% Compounding Annual Return -30.420% Drawdown 2.000% Expectancy -0.812 Net Profit -1.479% Sharpe Ratio -1.001 Probabilistic Sharpe Ratio 31.887% Loss Rate 91% Win Rate 9% Profit-Loss Ratio 1.14 Alpha 0.004 Beta 0.787 Annual Standard Deviation 0.078 Annual Variance 0.006 Information Ratio 1.007 Tracking Error 0.026 Treynor Ratio -0.099 Total Fees $1250.00 Estimated Strategy Capacity $200000.00 Lowest Capacity Asset OGCP VKET4LM50ZFP |
from datetime import timedelta from AlgorithmImports import ( QCAlgorithm, Resolution, DataNormalizationMode, FineFundamentalUniverseSelectionModel, AlphaModel, ConstantAlphaModel, InsightType, InsightDirection, EqualWeightingPortfolioConstructionModel, ImmediateExecutionModel, NullRiskManagementModel, OrderStatus ) class Quantmomentum(QCAlgorithm): def Initialize(self): self.UniverseSettings.Resolution = Resolution.Daily self.UniverseSettings.DataNormalizationMode = DataNormalizationMode.Raw self.SetStartDate(2014, 3, 25) # Set Start Date self.SetEndDate(2014, 4, 8) # Set End Date self.SetCash(100000) # Set Strategy Cash self.SetUniverseSelection(nyse_marketcap_breakpoint(self, percentile=0.4, debug=True)) self.SetAlpha(ConstantAlphaModel(InsightType.Price, InsightDirection.Up, timedelta(days=1))) self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel(Resolution.Daily)) self.SetExecution(ImmediateExecutionModel()) self.SetRiskManagement(NullRiskManagementModel()) def OnOrderEvent(self, orderEvent): if orderEvent.Status == OrderStatus.Filled: self.Debug("Purchased Stock: {0}".format(orderEvent.Symbol)) def nyse_marketcap_breakpoint(algorithm, *, percentile, nyse_codes=None, debug=False): if nyse_codes is None: nyse_codes = {'NYS'} def in_breakpoint_universe(fine_object): return (fine_object.SecurityReference.ExchangeId in nyse_codes and # NYSE only fine_object.SecurityReference.SecurityType == 'ST00000001' and # Common shares fine_object.SecurityReference.CommonShareSubType == None) # Only ordinary common shares. def set_coarse(coarse): all_coarse = [s for s in coarse] coarse_universe = [s.Symbol for s in all_coarse if s.HasFundamentalData] if debug: algorithm.Debug(f'Coarse universe ({algorithm.Time}) - {len(all_coarse)} coarse objects received, {len(coarse_universe)} with fundamentals.') return coarse_universe def set_fine(fine): all_fine = [s for s in fine] breakpoint_stocks = [s for s in all_fine if in_breakpoint_universe(s)] breakpoint_stocks.sort(key=lambda s: s.MarketCap) if breakpoint_stocks: index = int(len(breakpoint_stocks) * percentile) breakpoint_security = breakpoint_stocks[index] breakpoint = breakpoint_security.MarketCap else: breakpoint = 1e9 fine_universe = [f.Symbol for f in all_fine if f.MarketCap >= breakpoint] if debug: algorithm.Debug(f'Fine universe ({algorithm.Time}) - {len(all_fine)} fine objects received, {len(breakpoint_stocks)} in NYSE universe, {breakpoint} is breakpoint, resulting in {len(fine_universe)} in fine universe.') return fine_universe return FineFundamentalUniverseSelectionModel(set_coarse, set_fine) class QuantitativeMomentum(AlphaModel): def __init__(self, lookback_mo=12, reversal_mo=1, momentum_pct=0.1, quality_pct=0.5): self.lookback_mo = lookback_mo self.reversal_mo = reversal_mo self.momentum_pct = momentum_pct self.quality_pct = quality_pct def Update(self, algorithm, data): pass # Update all momentum for new data # Figure out NYSE breakpoint def OnSecuritiesChanged(self, algorithm, changes): pass # For all added securities: add a quantitative momentum data object # Prepopulate it with up to 252 days of trading data # For all removed securities: delete it.