| 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_insightsimport 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())