| Overall Statistics |
|
Total Trades 89 Average Win 0.01% Average Loss -0.01% Compounding Annual Return 0% Drawdown 946.100% Expectancy -0.515 Net Profit -955.605% Sharpe Ratio -0.033 Probabilistic Sharpe Ratio 0.393% Loss Rate 64% Win Rate 36% Profit-Loss Ratio 0.34 Alpha -2.437 Beta -3.251 Annual Standard Deviation 30.638 Annual Variance 938.691 Information Ratio -0.018 Tracking Error 30.645 Treynor Ratio 0.308 Total Fees $174.11 |
from alpha import LongShortCBOPAlpha
from universe import BestWorstCBOPLargeCap
class CashBasedOperatingProfitability(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2015, 8, 1)
self.SetEndDate(2015, 10, 15)
self.SetCash(1000000)
self.UniverseSettings.Resolution = Resolution.Minute
self.AddUniverseSelection(BestWorstCBOPLargeCap())
self.AddAlpha(LongShortCBOPAlpha())
self.Settings.RebalancePortfolioOnInsightChanges = False
self.SetPortfolioConstruction(InsightWeightingPortfolioConstructionModel(lambda time: None))
self.SetExecution(ImmediateExecutionModel())
self.SetBrokerageModel(BrokerageName.AlphaStreams)from Selection.FundamentalUniverseSelectionModel import FundamentalUniverseSelectionModel
class BestWorstCBOPLargeCap(FundamentalUniverseSelectionModel):
month = -1
def __init__(self, decile_denominator=10):
self.decile_denominator = decile_denominator
super().__init__(True)
def SelectCoarse(self, algorithm, coarse):
if self.month == algorithm.Time.month:
return Universe.Unchanged
self.month = algorithm.Time.month
return [x.Symbol for x in coarse if x.HasFundamentalData and x.Price > 5]
def SelectFine(self, algorithm, fine):
fine = [x for x in fine if (x.EarningReports.BasicAverageShares.ThreeMonths != 0 and \
x.EarningReports.BasicEPS.TwelveMonths != 0 and \
x.ValuationRatios.PERatio != 0 and \
x.FinancialStatements.IncomeStatement.TotalRevenue.TwelveMonths != 0 and \
x.FinancialStatements.IncomeStatement.SellingAndMarketingExpense.TwelveMonths != 0 and \
x.FinancialStatements.IncomeStatement.CostOfRevenue.TwelveMonths != 0 and \
x.FinancialStatements.IncomeStatement.GeneralAndAdministrativeExpense.TwelveMonths != 0)]
if len(fine) == 0:
return []
market_cap_by_symbol = {}
cbop_by_symbol = {}
# Market cap and cbop calc.
for stock in fine:
symbol = stock.Symbol
market_cap_by_symbol[symbol] = float(stock.CompanyProfile.MarketCap)
income_statement = stock.FinancialStatements.IncomeStatement
cbop_by_symbol[symbol] = income_statement.TotalRevenue.TwelveMonths - \
income_statement.SellingAndMarketingExpense.TwelveMonths - \
income_statement.CostOfRevenue.TwelveMonths - \
income_statement.GeneralAndAdministrativeExpense.TwelveMonths
# Sorting by market cap and cbop
top_market_cap = sorted(market_cap_by_symbol.items(), key = lambda x:x[1], reverse=True)[:int(len(market_cap_by_symbol)/2)]
sorted_by_cbop = sorted(top_market_cap, key = lambda x:cbop_by_symbol[x[0]], reverse=True)
decile = int(len(sorted_by_cbop)/self.decile_denominator)
longs = [symbol for symbol, _ in sorted_by_cbop[:decile]]
shorts = [symbol for symbol, _ in sorted_by_cbop[-decile:]]
return longs + shortsfrom dateutil.relativedelta import relativedelta
class LongShortCBOPAlpha(AlphaModel):
symbol_data_by_symbol = {}
month = -1
def Update(self, algorithm, data):
if data.Time.month == self.month:
return []
self.month = data.Time.month
# Filter for available data
has_data = {symbol: symbol_data for symbol, symbol_data in self.symbol_data_by_symbol.items() if data.ContainsKey(symbol)}
# Split into long/short from CBOP
sorted_by_cbop = sorted(has_data.items(), key=lambda x: x[1].CBOP, reverse=True)
half = int(len(sorted_by_cbop) / 2)
longs = [ symbol for symbol, _ in sorted_by_cbop[:half] ]
shorts = [ symbol for symbol, _ in sorted_by_cbop[-half:] ]
# Gather market cap info
market_cap_by_symbol = {symbol: symbol_data.MarketCap for symbol, symbol_data in has_data.items()}
total_market_cap = sum(market_cap_by_symbol.values())
# Generate insights
insights = []
hold_duration = Expiry.EndOfMonth(data.Time)
for symbol in longs:
weight = market_cap_by_symbol[symbol] / total_market_cap
insight = Insight.Price(symbol, hold_duration, InsightDirection.Up, None, None, None, weight)
insights.append(insight)
for symbol in shorts:
weight = market_cap_by_symbol[symbol] / total_market_cap
insight = Insight.Price(symbol, hold_duration, InsightDirection.Down, None, None, None, weight)
insights.append(insight)
return insights
def OnSecuritiesChanged(self, algorithm, changes):
for security in changes.AddedSecurities:
self.symbol_data_by_symbol[security.Symbol] = SymbolData(security)
for security in changes.RemovedSecurities:
self.symbol_data_by_symbol.pop(security.Symbol, None)
class SymbolData:
def __init__(self, security):
self.security = security
@property
def MarketCap(self):
return self.security.Fundamentals.CompanyProfile.MarketCap
@property
def CBOP(self):
income_statement = self.security.Fundamentals.FinancialStatements.IncomeStatement
return income_statement.TotalRevenue.TwelveMonths - \
income_statement.SellingAndMarketingExpense.TwelveMonths - \
income_statement.CostOfRevenue.TwelveMonths - \
income_statement.GeneralAndAdministrativeExpense.TwelveMonths