Overall Statistics |
Total Trades 1406 Average Win 0.00% Average Loss 0.00% Compounding Annual Return 349.382% Drawdown 4.900% Expectancy -0.853 Net Profit 4.203% Sharpe Ratio 6.946 Probabilistic Sharpe Ratio 66.440% Loss Rate 93% Win Rate 7% Profit-Loss Ratio 1.11 Alpha -1.526 Beta 1.097 Annual Standard Deviation 0.335 Annual Variance 0.112 Information Ratio -5.911 Tracking Error 0.201 Treynor Ratio 2.124 Total Fees $1453.25 |
import pandas as pd from datetime import datetime from QuantConnect import Expiry def normalise(series, equal_ls=True): if equal_ls: series -= series.mean() sum = series.abs().sum() return series.apply(lambda x: x/sum) class ValueAlphaModel(AlphaModel): def __init__(self): self.securities = [] def Update(self, algorithm, data): algorithm.Log("Generating alphas...") algorithm.Log(f"{len(algorithm.ActiveSecurities)} securities in ActiveSecurities") algorithm.Log(f"{len(self.securities)} securities in self.securities") insights = [] fcf_y = pd.DataFrame.from_records( [ { 'symbol': security.Symbol, 'fcf_y': security.Fundamentals.ValuationRatios.CashReturn } for security in self.securities ]) fcf_y['fcf_y'] = normalise(fcf_y['fcf_y'], True) for i, security in fcf_y.iterrows(): direction = InsightDirection.Up if security['fcf_y'] > 0 else InsightDirection.Down symbol = security['symbol'] weight = abs(security['fcf_y']) insight = Insight.Price(security['symbol'], timedelta(days=1), InsightDirection.Up, None, None, "ValueAlphaModel", weight) insights.append(insight) securities = set([i.Symbol for i in insights]) algorithm.Debug(f"Generated {len(insights)} insights for {len(securities)} securities") return insights def OnSecuritiesChanged(self, algorithm, changes): algorithm.Log(f"{len(changes.AddedSecurities)} securities to add") algorithm.Log(f"{len(changes.RemovedSecurities)} securities to remove") for security in changes.AddedSecurities: self.securities.append(security) for security in changes.RemovedSecurities: if security in self.securities: self.securities.remove(security)
from QuantConnect.Data.UniverseSelection import * from Selection.FundamentalUniverseSelectionModel import FundamentalUniverseSelectionModel class FactorUniverseSelectionModel(FundamentalUniverseSelectionModel): def __init__(self): super().__init__(True, None, None) def SelectCoarse(self, algorithm, coarse): algorithm.Log("Generating universe...") universe = self.FilterDollarVolume(coarse) return [c.Symbol for c in universe] def SelectFine(self, algorithm, fine): universe = self.FilterFactor(self.FilterFinancials(fine)) algorithm.Log(f"Universe consists of {len(universe)} securities") return [f.Symbol for f in universe] def FilterDollarVolume(self, coarse): sorted_dollar_volume = sorted([c for c in coarse if c.HasFundamentalData], key=lambda c: c.DollarVolume, reverse=True) return sorted_dollar_volume[:1000] def FilterFinancials(self, fine): filter_financials = [f for f in fine if f.AssetClassification.MorningstarSectorCode != MorningstarSectorCode.FinancialServices] return filter_financials def FilterFactor(self, fine): filter_factor = sorted(fine, key=lambda f: f.ValuationRatios.CashReturn, reverse=True) return filter_factor[:2] + filter_factor[-2:]
from clr import AddReference AddReference("QuantConnect.Common") AddReference("QuantConnect.Algorithm.Framework") import pandas as pd from datetime import timedelta from QuantConnect import Resolution, Extensions from QuantConnect.Algorithm.Framework.Alphas import * from QuantConnect.Algorithm.Framework.Portfolio import * class OptimisationPortfolioConstructionModel(PortfolioConstructionModel): def __init__(self, rebalancingParam = Resolution.Daily): self.SetRebalancing(rebalancingParam) def SetRebalancing(self, rebalancingParam): if isinstance(rebalancingParam, int): rebalancingParam = Extensions.ToTimeSpan(rebalancingParam) if isinstance(rebalancingParam, timedelta): rebalancingFunc = lambda dt: dt + rebalancingParam if rebalancingFunc: self.SetRebalancingFunc(rebalancingFunc) def CreateTargets(self, algorithm, insights): algorithm.Log("Generating targets...") targets = [] active_insights = self.GetActiveInsights(algorithm, insights) if len(active_insights) == 0: algorithm.Log("No active insights") return targets alpha_portfolio = self.CalcAlphaPortfolio(algorithm, active_insights) for symbol, weight in alpha_portfolio.iteritems(): target = PortfolioTarget.Percent(algorithm, symbol, weight) algorithm.Log(f"Target - {symbol} {weight} {target}") if target is not None: targets.append(target) algorithm.Log(f"Created a portfolio of {len(targets)} targets") return targets def CalcAlphaPortfolio(self, algorithm, active_insights): portfolio = pd.Series([i.Weight if i.Direction == InsightDirection.Up else -i.Weight for i in active_insights], index=[i.Symbol for i in active_insights]) port_sum = portfolio.abs().sum() if port_sum != 1: algorithm.Log(f"Alpha insight weights don't add up to 1: {port_sum}") portfolio /= port_sum return portfolio def GetActiveInsights(self, algorithm, insights): active_insights = [i for i in insights if i.IsActive(algorithm.UtcTime)] return active_insights
import pandas as pd from datetime import timedelta from universe_selection import FactorUniverseSelectionModel from alpha_model import ValueAlphaModel from portfolio_construction import OptimisationPortfolioConstructionModel class TradingBot(QCAlgorithm): def Initialize(self): self.SetStartDate(2003, 1, 1) self.SetEndDate(2003, 1, 10) self.SetCash(100000) self.UniverseSettings.Leverage = 1 # Data resolution self.UniverseSettings.Resolution = Resolution.Minute self.Settings.RebalancePortfolioOnInsightChanges = False self.Settings.RebalancePortfolioOnSecurityChanges = False # Universe selection model self.AddUniverseSelection(FactorUniverseSelectionModel()) self.securities = [] # Alpha model self.AddAlpha(ValueAlphaModel()) # Portfolio construction model #self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel()) self.SetPortfolioConstruction(OptimisationPortfolioConstructionModel()) # Execution model self.SetExecution(ImmediateExecutionModel())