| Overall Statistics |
|
Total Trades 81 Average Win 0.02% Average Loss -0.03% Compounding Annual Return 341.808% Drawdown 1.900% Expectancy -0.292 Net Profit 4.154% Sharpe Ratio 10.163 Probabilistic Sharpe Ratio 79.706% Loss Rate 56% Win Rate 44% Profit-Loss Ratio 0.62 Alpha 2.463 Beta -0.078 Annual Standard Deviation 0.216 Annual Variance 0.046 Information Ratio -3.886 Tracking Error 0.341 Treynor Ratio -28.221 Total Fees $174.27 |
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(security['symbol'], Expiry.EndOfDay, InsightType.Price, direction)
insight.Weight = weight
insights.append(insight)
securities = set([i.Symbol for i in insights])
algorithm.Log(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[:20] + filter_factor[-20:]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)
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.Daily
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(OptimisationPortfolioConstructionModel())
# Execution model
self.SetExecution(ImmediateExecutionModel())