| Overall Statistics |
|
Total Trades 0 Average Win 0% Average Loss 0% Compounding Annual Return 0% Drawdown 0% Expectancy 0 Net Profit 0% Sharpe Ratio 0 Loss Rate 0% Win Rate 0% Profit-Loss Ratio 0 Alpha 0 Beta 0 Annual Standard Deviation 0 Annual Variance 0 Information Ratio 0 Tracking Error 0 Treynor Ratio 0 Total Fees $0.00 |
from System import *
from System.Collections.Generic import List
from QuantConnect import *
from QuantConnect.Algorithm import QCAlgorithm
from QuantConnect.Data.UniverseSelection import *
import pandas as pd
import numpy as np
class CoarseFineFundamentalComboAlgorithm(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2010,01,01) #Set Start Date
self.SetEndDate(2014,06,01) #Set End Date
self.SetCash(50000) #Set Strategy Cash
self.UniverseSettings.Resolution = Resolution.Daily
self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction)
self.AddEquity("SPY")
self.numOfCourseSymbols = 110
self.numOfPortfolio = 5
self.numOfPortSymbols = self.numOfPortfolio * 15
self.numOfMonths = 48
self._changes = SecurityChanges.None
self.flag1 = 1
self.flag2 = 0
self.pos = 0
self.df_return = pd.DataFrame(index = range(self.numOfPortfolio+1))
self.Schedule.On(self.DateRules.MonthStart("SPY"), self.TimeRules.AfterMarketOpen("SPY"), Action(self.Rebalancing))
# sort the data by daily dollar volume and take the top 'NumberOfSymbols'
def CoarseSelectionFunction(self, coarse):
if self.flag1:
CoarseWithFundamental = [x for x in coarse if x.HasFundamentalData]
sortedByVolume = sorted(CoarseWithFundamental, key=lambda x: x.DollarVolume, reverse=True)
top = sortedByVolume[:self.numOfCourseSymbols]
# we need to return only the symbol objects
list = List[Symbol]()
for x in top:
list.Add(x.Symbol)
return list
else:
return(List[Symbol]())
def FineSelectionFunction(self, fine):
if self.flag1:
self.flag1 = 0
self.flag2 = 1
# filter the fine by deleting equities wit zero factor value
filtered_fine = [x for x in fine if x.ValuationRatios.PERatio != 0 ]
# sort the fine by reverse order of factor value
sorted_fine = sorted(filtered_fine, key=lambda x: x.ValuationRatios.PERatio, reverse=True)
self.symbol = [str(x.Symbol.Value) for x in sorted_fine]
# factor_value = [x.ValuationRatios.PERatio for x in sorted_fine]
self.pos = self.pos + 1
return (List[Symbol]())
else:
return (List[Symbol]())
def Rebalancing(self):
self.flag1 = 1
def OnData(self, data):
if self.pos > 0:
if self.flag2 == 1:
self.flag2 = 0
sorted_symbol = self.symbol
self.AddEquity("SPY") # add benchmark
for x in sorted_symbol:
self.AddEquity(x)
history = self.History(21,Resolution.Daily)
monthly_return =[]
new_symbol_list =[]
for j in range(len(sorted_symbol)):
try:
daily_price = []
for slice in history:
bar = slice[sorted_symbol[j]]
daily_price.append(float(bar.Close))
new_symbol_list.append(sorted_symbol[j])
monthly_return.append(daily_price[-1] / daily_price[0] - 1)
except:
self.Log("No history data for " + str(sorted_symbol[j]))
del daily_price
monthly_return = monthly_return[:self.numOfPortSymbols]
# devide the stocks into n portfolios
reshape_return = np.reshape(monthly_return, (self.numOfPortfolio, len(monthly_return)/self.numOfPortfolio))
# calculate the average return of different portfolios
port_avg_return = np.mean(reshape_return,axis=1).tolist()
# add return of "SPY" as the benchmark to the end of the return list
benchmark_syl = self.AddEquity("SPY").Symbol
history_benchmark = self.History(21,Resolution.Daily)
benchmark_daily_price = [float(slice[benchmark_syl].Close) for slice in history_benchmark]
benchmark_monthly_return = (benchmark_daily_price[-1]/benchmark_daily_price[0]) - 1
port_avg_return.append(benchmark_monthly_return)
self.df_return[str(self.pos)] = port_avg_return
if self.pos == self.numOfMonths:
self.Log(str(self.df_return))
result = self.calculate_criteria(self.df_return)
self.Log(str(result))
def calculate_criteria(self,df_port_return):
total_return = (df_port_return + 1).T.cumprod().iloc[-1,:] - 1
self.Log(str(total_return))
annual_return = (total_return+1)**(1./6)-1
excess_return = annual_return - np.array(annual_return)[-1]
correlation = annual_return[0:5].corr(pd.Series([5,4,3,2,1],index = annual_return[0:5].index))
# higher factor with higher return
if np.array(total_return)[0] > np.array(total_return)[-2]:
loss_excess = df_port_return.iloc[-2,:] - df_port_return.iloc[-1,:]
win_excess = df_port_return.iloc[0,:] - df_port_return.iloc[-1,:]
loss_prob = loss_excess[loss_excess<0].count()/float(len(loss_excess))
win_prob = win_excess[win_excess>0].count()/float(len(win_excess))
win_port_excess_return = np.array(excess_return)[0]
loss_port_excess_return = np.array(excess_return)[-2]
# higher factor with lower return
else:
loss_excess = df_port_return.iloc[0,:] - df_port_return.iloc[-1,:]
win_excess = df_port_return.iloc[-2,:] - df_port_return.iloc[-1,:]
loss_prob = loss_excess[loss_excess<0].count()/float(len(loss_excess))
win_prob = win_excess[win_excess>0].count()/float(len(win_excess))
win_port_excess_return = np.array(excess_return)[-2]
loss_port_excess_return = np.array(excess_return)[0]
test_result = {"correelation":[],
"win probality":[],
"loss probality":[],
"win portfolio excess return":[],
"loss portfolio excess return":[]}
test_result["correelation"].append(correlation)
test_result["win probality"].append(win_prob)
test_result["loss probality"].append(loss_prob)
test_result["win portfolio excess return"].append(win_port_excess_return)
test_result["loss portfolio excess return"].append(loss_port_excess_return)
return pd.DataFrame(test_result)