| Overall Statistics |
|
Total Trades
4494
Average Win
0.13%
Average Loss
-0.15%
Compounding Annual Return
15.452%
Drawdown
34.300%
Expectancy
0.366
Net Profit
348.611%
Sharpe Ratio
0.913
Probabilistic Sharpe Ratio
30.865%
Loss Rate
27%
Win Rate
73%
Profit-Loss Ratio
0.87
Alpha
0.152
Beta
-0.103
Annual Standard Deviation
0.152
Annual Variance
0.023
Information Ratio
0.032
Tracking Error
0.228
Treynor Ratio
-1.347
Total Fees
$300.10
Estimated Strategy Capacity
$6300000.00
Lowest Capacity Asset
FPH WKELFN09PUN9
|
# https://quantpedia.com/strategies/alpha-cloning-following-13f-fillings/
#
# Create a universe of active mutual fund managers.
# Use 13F filings to identify the “best idea” stocks for each manager.
# Invest in the stocks, which are the “best ideas” for most of the managers.
#
# QC Implementation:
# - Investor preferences was downloaded from https://www.insidermonkey.com/hedge-fund/browse/A/
# - Investors list consists of first 10 investors in each browse letter and
# from lists in basic and premium cards on https://www.gurufocus.com/guru/list
# - Investor preferences are modeled to be known 2 months after announcement.
import numpy as np
from dateutil.relativedelta import relativedelta
class AlphaCloningFollowing13FFillings(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2011, 1, 1)
self.SetCash(100000)
self.weight = {}
self.investors_preferences = {}
self.symbol = self.AddEquity('SPY', Resolution.Daily).Symbol
csv_string_file = self.Download('data.quantpedia.com/backtesting_data/investor_preferences/investors_preferences.csv')
lines = csv_string_file.split('\r\n')
# Skip csv header in loop
for line in lines[1:]:
line_split = line.split(';')
date = datetime.strptime(line_split[0], "%d.%m.%Y").date()
self.investors_preferences[date] = {}
for ticker in line_split[1:]:
if ticker not in self.investors_preferences[date]:
self.investors_preferences[date][ticker] = 0
self.investors_preferences[date][ticker] += 1
self.months_lag = 2 # Lag for getting investors preferences report
self.month_counter = 0
self.selection_flag = False
self.UniverseSettings.Resolution = Resolution.Daily
self.AddUniverse(self.CoarseSelectionFunction)
self.Schedule.On(self.DateRules.MonthStart(self.symbol), self.TimeRules.AfterMarketOpen(self.symbol), self.Selection)
def OnSecuritiesChanged(self, changes):
for security in changes.AddedSecurities:
security.SetFeeModel(CustomFeeModel(self))
security.SetLeverage(5)
def CoarseSelectionFunction(self, coarse):
if not self.selection_flag:
return Universe.Unchanged
selected_report = None
current_date = self.Time.date() + relativedelta(months=self.months_lag)
for date in self.investors_preferences:
# Get latest report
if date < current_date:
selected_report = self.investors_preferences[date]
# Report might not be selected, because there are no data for that date
if selected_report is None:
return Universe.Unchanged
# Select universe based on report
selected = [x.Symbol for x in coarse if x.Symbol.Value in selected_report]
# Calculate total preferences votes for selected report
total_preferences_votes = sum([x[1] for x in selected_report.items()])
# Calculate weight for each stock in selected universe
for symbol in selected:
# weight = total stock preferences votes / total investor votes in selected report
self.weight[symbol] = selected_report[symbol.Value] / total_preferences_votes
return selected
def OnData(self, data):
if not self.selection_flag:
return
self.selection_flag = False
# Trade Execution
stocks_invested = [x.Key for x in self.Portfolio if x.Value.Invested]
for symbol in stocks_invested:
if symbol not in self.weight:
self.Liquidate(symbol)
for symbol, w in self.weight.items():
if self.Securities[symbol].Price != 0 and self.Securities[symbol].IsTradable:
self.SetHoldings(symbol, w)
self.weight.clear()
def Selection(self):
# Rebalance quarterly
if self.month_counter % 3 == 0:
self.selection_flag = True
self.month_counter += 1
# Custom fee model
class CustomFeeModel(FeeModel):
def GetOrderFee(self, parameters):
fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005
return OrderFee(CashAmount(fee, "USD"))