SSRN Id2802753
SSRN Id2802753
SSRN Id2802753
Abstract
We give complete algorithms and source code for constructing (multilevel)
statistical industry classifications, including methods for fixing the number
of clusters at each level (and the number of levels). Under the hood there
are clustering algorithms (e.g., k-means). However, what should we cluster?
Correlations? Returns? The answer turns out to be neither and our backtests
suggest that these details make a sizable difference. We also give an algorithm
and source code for building “hybrid” industry classifications by improving
off-the-shelf “fundamental” industry classifications by applying our statistical
industry classification methods to them. The presentation is intended to be
pedagogical and geared toward practical applications in quantitative trading.
1
Zura Kakushadze, Ph.D., is the President of Quantigicr Solutions LLC, and a Full Professor
at Free University of Tbilisi. Email: zura@quantigic.com
2
Willie Yu, Ph.D., is a Research Fellow at Duke-NUS Medical School. Email: willie.yu@duke-
nus.edu.sg
3
DISCLAIMER: This address is used by the corresponding author for no purpose other than
to indicate his professional affiliation as is customary in publications. In particular, the contents
of this paper are not intended as an investment, legal, tax or any other such advice, and in no
way represent views of Quantigicr Solutions LLC, the website www.quantigic.com or any of their
other affiliates.
The beauty of such “binary” industry classifications (generally, with P levels) is that
the “clusters” (in the case of BICS, sub-industries, industries and sectors) can be
used to identify blocks (sub-matrices) in the sample correlation matrix Ψij of stock
returns.14 E.g., for sub-industries the binary matrix δG(i),A defines such blocks.
10
However, there is variability in the performance of different industry classifications.
11
Here we are assuming that each stock belongs to one and only one “cluster”. Generally,
this assumption can be relaxed thereby allowing for “conglomerates” that belong to multiple sub-
industries, industries, sectors, etc. However, this is not required for our purposes here.
12
The branches in this hierarchy tree are assumed to have equal lengths. More generally, we
can have branches of nonuniform lengths. However, shorter branches can always be extended to
the length of the longest branch(es) by allowing single-element (including single-stock) “clusters”.
13
Bloomberg Industry Classification System.
14
And this is useful in constructing risk models for portfolio optimization (Kakushadze, 2015b).
3.1 K-means
A popular clustering algorithm is k-means (Steinhaus, 1957), (Lloyd, 1957), (Forgy,
1965), (MacQueen, 1967), (Hartigan, 1975), (Hartigan and Wong, 1979), (Lloyd,
1982). The basic idea behind k-means is to partition N observations into K clusters
such that each observation belongs to the cluster with the nearest mean. Each of the
N observations is actually a d-vector, so we have an N × d matrix Xis , i = 1, . . . , N ,
s = 1, . . . , d. Let Ca be the K clusters, Ca = {i|i ∈ Ca }, a = 1, . . . , K. Then
k-means attempts to minimize
K XX
X d
g= (Xis − Yas )2 (4)
a=1 i∈Ca s=1
where
1 X
Yas = Xis (5)
na i∈C
a
are the cluster centers (i.e., cross-sectional means),16 and na = |Ca | is the number
of elements in the cluster Ca . In (4) the measure of “closeness” is chosen to be the
Euclidean distance between points in Rd , albeit other measures are possible.
One “drawback” of k-means is that it is not a deterministic algorithm. Generi-
cally, there are copious local minima of g in (4) and the algorithm only guarantees
that it will converge to a local minimum, not the global one. Being an iterative
algorithm, k-means starts with a random or user-defined set of the centers Yas at
the initial iteration. However, as we will see, this “drawback” actually adds value.
15
Commercially available industry classifications such as GICS and ICB come at nontrivial cost.
The underlying SIC data is available from SEC for free, albeit only by company names, not by
ticker symbols. It takes considerable effort to download this data and transform it into an actual
industry classification. Alternatively, it can be purchased from commercial providers.
16
Throughout this paper “cross-sectional” refers to “over the index i”.
bis = Ris
R (6)
σi ui
σi
ui = (7)
v
v = exp(Median(ln(σi )) − 3 MAD(ln(σi ))) (8)
[R(µ)]i(µ),s
[R(µ)]
b i(µ),s = 2
(11)
σi(µ)
2
σi(µ) = Var([R(µ)]i(µ),s ) (12)
These two definitions produce very similar results in our backtests (see below).
4 Backtests
Let us backtest the above algorithms for constructing statistical industry classifica-
tion by utilizing the same backtesting procedure as in (Kakushadze, 2015b). The
remainder of this subsection very closely follows most parts of Section 6 thereof.30
4.1 Notations
Let Pis be the time series of stock prices, where i = 1, . . . , N labels the stocks,
and s = 1, 2, . . . labels the trading dates, with s = 1 corresponding to the most
recent date in the time series. The superscripts O and C (unadjusted open and
close prices) and AO and AC (open and close prices fully adjusted for splits and
dividends) will distinguish the corresponding prices, so, e.g., PisC is the unadjusted
29
A brute force algorithm where at each step rows and columns are deleted from the matrix
D(i, j) is too slow. The R source code we give in Appendix C is substantially more efficient than
that. However, it is still substantially slower than the k-means based algorithms we discuss above.
30
We “rehash” it here not to be repetitive but so that our presentation here is self-contained.
10
This return will be used in the definition of the expected return in our mean-reversion
alpha. We will also need the close-to-close return
An out-of-sample (see below) time series of these returns will be used in constructing
the risk models. All prices in the definitions of Eis and Ris are fully adjusted.
We assume that: i) the portfolio is established at the open31 with fills at the
open prices PisO ; ii) it is liquidated at the close on the same day – so this is a purely
intraday alpha – with fills at the close prices PisC ; and iii) there are no transaction
costs or slippage – our aim here is not to build a realistic trading strategy, but to
test relative performance of various statistical industry classifications. The P&L for
each stock C
Pis
Πis = His −1 (15)
PisO
where His are the dollar holdings. The shares bought plus sold (establishing plus
liquidating trades) for each stock on each day are computed via Qis = 2|His |/PisO .
We take m = 21 (i.e., one month), and then take our universe to be the top 2000 tick-
ers by ADDV. To ensure that we do not inadvertently introduce a universe selection
bias, we rebalance monthly (every 21 trading days, to be precise). I.e., we break our
5-year backtest period (see below) into 21-day intervals, we compute the universe
using ADDV (which, in turn, is computed based on the 21-day period immediately
preceding such interval), and use this universe during the entire such interval. We
do have the survivorship bias as we take the data for the universe of tickers as of
9/6/2014 that have historical pricing data on http://finance.yahoo.com (accessed on
9/6/2014) for the period 8/1/2008 through 9/5/2014. We restrict this universe to
31 O AO
This is a so-called “delay-0” alpha: the same price, Pis (or adjusted Pis ), is used in com-
puting the expected return (via Eis ) and as the establishing fill price.
32
In practical applications, the trading universe of liquid stocks typically is selected based on
market cap, liquidity (ADDV), price and other (proprietary) criteria.
11
4.3 Backtesting
We run our simulations over a period of 5 years (more precisely, 1260 trading days
going back from 9/5/2014, inclusive). The annualized return-on-capital (ROC) is
computed as the average daily P&L divided by the intraday investment level I (with
no leverage) and multiplied by 252. The √annualized Sharpe Ratio (SR) is computed
as the daily Sharpe ratio multiplied by 252. Cents-per-share (CPS) is computed
as the total P&L in cents (not dollars) divided by the total shares traded.
33
The choice of the backtesting window is intentionally taken to be exactly the same as in
(Kakushadze, 2015b) to simplify various comparisons, which include the results therefrom.
34
Here we are after the relative outperformance, and it is reasonable to assume that, to the
leading order, individual performances are affected by the survivorship bias approximately equally
as the construction of all alphas and risk models is “statistical” and oblivious to the universe.
35
In (Kakushadze, 2015b) BICS is used for the industry classification. Here we simply plug
in the statistical industry classification instead of BICS. In the case of a single-level industry
classification, we can either add the second level consisting of the “market” with the N × 1 unit
matrix as the loadings matrix; or, equivalently, we can use the option mkt.fac = T in the R
function qrm.het() in Appendix B of (Kakushadze, 2015b), which accomplishes this internally.
12
where Ais is ADDV defined in (16). In the presence of bounds computing Hi requires
an iterative procedure and we use the R code in Appendix C of (Kakushadze, 2015b).
13
14
I.e., we approximate Ψij (which is singular) via Γij (which is positive-definite as all
ξi2 > 0 and are fixed from the requirement that Γii ≡ 1). The question then is,
what should F be? One simple (“minimization” based) algorithm for fixing F is
given in (Kakushadze, 2015b). Another, even simpler algorithm recently proposed
in (Kakushadze and Yu, 2016b), is based on eRank (effective rank) defined below.40
where λ(a) are the L positive eigenvalues of Z, and H has the meaning of the (Shan-
non a.k.a. spectral) entropy (Campbell, 1960), (Yang et al, 2005).
The meaning of eRank(Z) is that it is a measure of the effective dimensionality
of the matrix Z, which is not necessarily the same as the number L of its positive
eigenvalues, but often is lower. This is due to the fact that many returns can be
highly correlated (which manifests itself by a large gap in the eigenvalues) thereby
further reducing the effective dimensionality of the correlation matrix.
40
For prior works on fixing F , see, e.g., (Connor and Korajczyk, 1993) and (Bai and Ng, 2002).
15
What about Kµ , 1 < µ < P ? Doing anything overly complicated here would be
overkill. Here is a simple prescription (assuming K1 > KP ):42
h 1
i P −1
Kµ = K1P −µ KPµ−1 , µ = 1, . . . , P (30)
We give the R source code for building “bottom-up” statistical industry classifica-
tions using this prescription in Appendix A. Table 7 summarized simulation results
for P = 2, 3, 4, 5. It is evident that the number of levels is not a driver here. The
results are essentially the same as for K1 = 100 (recall that N = 2000 and d = 21
in our case) in Tables 2 and 3. Table 8 isolates the K dependence and suggests that
the performance peaks around K = 100. Again, there is no magic bullet here.43
5.3 Comparisons
Let us compare the (very stable) results we obtained for statistical industry classifi-
cations with two “benchmarks”: statistical risk models (Kakushadze and Yu, 2016b)
and heterotic risk models with BICS used as the industry classification (Kakushadze,
41
The number of factors F essentially measures the effective number of degrees of freedom in
the underlying time series of returns Ris . Hence identification of KP with this number.
42
I.e.,
√ Kµ are (up to rounding) equidistant on the log scale. For P = 3 the “midpoint”
K2 = K1 KP is simply the geometric mean. With this prescription, we can further fix P via
some heuristic, e.g., take maximal P such that the difference KP −1 − KP ≥ ∆, where ∆ is preset,
say, ∆ = KP . For K1 = 100 and KP = 10, this would give us P = 4 with K2 = 46 and K3 = 22.
43
Note from Table 8 that too little granularity lowers the Sharpe ratio due to insufficient
coverage of the risk space, while too much granularity lowers cents-per-share due to overtrading.
16
17
We then split each sub-industry with κA > 1 into κA clusters. Table 10 summarizes
the simulation results for 14 runs. This evidently improves performance. Table 11
gives summaries of top 10 most populous sub-industries before and after statistical
clustering based on 60 datapoints at the end of each 21-trading-day interval in our
backtests (recall that we have 1260 = 60 × 21 trading days – see Section 4). The
average numbers of sub-industries are 165.45 before and 184.1 after clustering.
7 Concluding Remarks
In this paper we discuss all sorts of nuances in constructing statistical industry clas-
sifications. Under the hood we have clustering algorithms. However, it is precisely
those nuances that make a sizable difference. E.g., if we naively cluster Ris , we get
a highly suboptimal result compared with clustering R eis = Ris /σi , which in turn
2
underperforms clustering R bis = Ris /σ . In this regard, let us tie up a “loose end”
i
here: what if we cluster Ris = Ris /σi3 ? It underperforms clustering R bis . Thus,
a typical run for a 3-level “bottom-up” classification with target cluster numbers
K1 = 100, K2 = 30 and K3 = 10 based on clustering Ris and aggregating 100
samplings produces the following: ROC = 40.686, SR = 15.789 and CPS = 2.075.
So, suppressing returns Ris by σi2 indeed appears to be optimal – for the intuitive
reasons we discussed above. We saw the same in the context of statistical risk
models. In this regard, it would be interesting to explore this avenue in the context of
heterotic risk models (Kakushadze, 2015b) and the more general (heterotic CAPM)
construction of (Kakushadze and Yu, 2016a). In the latter framework, it would be
interesting to utilize an aggregated (non-binary) matrix Ω e ia (see Subsection 3.3.3).
These ideas are outside of the scope hereof and we hope to return to them elsewhere.
18
19
for(i in 1:num.try)
{
res <- qrm.calc.kmeans.ind(norm.ret, k, iter.max)
if(num.try == 1)
return(res$ind)
if(i == 1)
{
comb.cent <- res$centers
comb.ind <- res$ind
}
else
{
comb.cent <- rbind(comb.cent, res$centers)
comb.ind <- cbind(comb.ind, res$ind)
}
}
20
for(i in 1:length(cl))
z[, cl[i]] <- z[, cl[i]] + comb.ind[, i]
q <- colSums(z)
for(i in 1:nrow(z))
{
take <- z[i, ] == max(z[i, ])
take <- take & q == max(q[take])
ix <- 1:ncol(z)
ix <- min(ix[take])
z[i, ] <- 0
z[i, ix] <- 1
}
z <- z[, colSums(z) > 0]
return(z)
}
for(i in 1:length(k))
{
21
if(i > 1)
{
ind.list[[i]] <- ind.list[[i - 1]] %*% ind.list[[i]]
take <- ind.list[[i]] > 0
ind.list[[i]][take] <- 1
}
}
return(ind.list)
}
22
if(p == 1)
k <- k1
else
{
q <- ((p - 1):0) / (p - 1)
k <- round(k1^q * kp^(1 - q))
}
if(k[p] == 1)
k <- k[-p]
if(top.down)
{
k1 <- c(k[-1], 1)
k <- round(k / k1)[length(k):1]
ind.list <- qrm.stat.class(ret, k,
iter.max = iter.max, num.try = num.try)
}
else
ind.list <- qrm.stat.ind.class.all(ret, k,
iter.max = iter.max, num.try = num.try, do.demean = do.demean)
return(ind.list)
}
23
tmp[take, ] <- y
ind1 <- cbind(ind1, tmp)
}
24
for(lvl in 2:p)
{
for(a in 1:ncol(ind[[lvl - 1]]))
{
take <- ind[[lvl - 1]][, a] > 0
tmp.k <- sum(take)
if(tmp.k <= k[lvl])
{
ind[[lvl]] <- cbind(ind[[lvl]], as.numeric(take))
next
}
x <- matrix(ret[take, ], tmp.k, ncol(ret))
norm.x <- qrm.calc.norm.ret(x)
tmp.ind <- qrm.stat.ind.class(x, k[lvl],
iter.max, num.try = num.try)
if(length(tmp.ind) > tmp.k)
tmp <- matrix(0, n, ncol(tmp.ind))
else
25
for(lvl in p:2)
ind.list[[p - lvl + 1]] <- ind[[lvl]]
return(ind.list)
}
for(i in 1:length(k))
{
ind.list[[i]] <- qrm.stat.clust(ret, k[i],
demean.ret = do.demean[i])
if(norm.cl.ret)
ret <- t(ind.list[[i]]) %*% qrm.calc.norm.ret(ret)
else
ret <- t(ind.list[[i]]) %*% ret
if(i > 1)
26
return(ind.list)
}
27
if(demean.ret)
ret <- t(t(ret) - colMeans(ret))
n <- nrow(ret)
v <- 1:n
m <- 0
count <- 0
w <- rep(0, n)
set.y <- F
while(count < n)
{
if(m < k)
y1 <- y
else if(!set.y)
{
set.y <- T
q <- v[w == 0]
n1 <- length(q)
u <- q + matrix((q - 1) * n, n1, n1, byrow = T)
take <- upper.tri(u, T)
u <- as.vector(u[!take])
take <- !(y %in% u)
y1 <- y[take]
}
else
28
ix <- extract.ix(y1)
q <- v[w > 0]
if(w[ix[1]] > 0)
{
count <- count + 1
w[p <- ix[2]] <- w[ix[1]]
take <- calc.take(n, p, q)
}
else if(w[ix[2]] > 0)
{
count <- count + 1
w[p <- ix[1]] <- w[ix[2]]
take <- calc.take(n, p, q)
}
else
{
m <- m + 1
count <- count + 2
w[ix] <- m
take <- c(calc.take(n, ix[1], q), calc.take(n, ix[2], q))
}
if(return.clust)
return(w)
k <- min(k, m)
z <- matrix(NA, n, k)
for(j in 1:k)
29
return(z)
}
D DISCLAIMERS
Wherever the context so requires, the masculine gender includes the feminine and/or
neuter, and the singular form includes the plural and vice versa. The author of this
paper (“Author”) and his affiliates including without limitation Quantigicr Solu-
tions LLC (“Author’s Affiliates” or “his Affiliates”) make no implied or express
warranties or any other representations whatsoever, including without limitation
implied warranties of merchantability and fitness for a particular purpose, in con-
nection with or with regard to the content of this paper including without limitation
any code or algorithms contained herein (“Content”).
The reader may use the Content solely at his/her/its own risk and the reader
shall have no claims whatsoever against the Author or his Affiliates and the Author
and his Affiliates shall have no liability whatsoever to the reader or any third party
whatsoever for any loss, expense, opportunity cost, damages or any other adverse
effects whatsoever relating to or arising from the use of the Content by the reader
including without any limitation whatsoever: any direct, indirect, incidental, spe-
cial, consequential or any other damages incurred by the reader, however caused
and under any theory of liability; any loss of profit (whether incurred directly or
indirectly), any loss of goodwill or reputation, any loss of data suffered, cost of pro-
curement of substitute goods or services, or any other tangible or intangible loss;
any reliance placed by the reader on the completeness, accuracy or existence of the
Content or any other effect of using the Content; and any and all other adversities
or negative effects the reader might encounter in using the Content irrespective of
whether the Author or his Affiliates is or are or should have been aware of such
adversities or negative effects.
The R code included in Appendix A, Appendix B and Appendix C hereof is part
of the copyrighted R code of Quantigicr Solutions LLC and is provided herein with
the express permission of Quantigicr Solutions LLC. The copyright owner retains all
rights, title and interest in and to its copyrighted source code included in Appendix
A, Appendix B and Appendix C hereof and any and all copyrights therefor.
References
Bai, J. and Ng, S. (2002) Determining the number of factors in approximate
factor models. Econometrica 70(1): 191-221.
30
Campbell, L.L. (1960) Minimum coefficient rate for stationary random pro-
cesses. Information and Control 3(4): 360-371.
Connor, G. and Korajczyk, R.A. (1993) A Test for the Number of Factors in
an Approximate Factor Model. The Journal of Finance 48(4): 1263-1291.
Forgy, E.W. (1965) Cluster analysis of multivariate data: efficiency versus in-
terpretability of classifications. Biometrics 21(3): 768-769.
Goutte, C., Hansen, L.K., Liptrot, M.G. and Rostrup, E. (2001) Feature-Space
Clustering for fMRI Meta-Analysis. Human Brain Mapping 13(3): 165-183.
Grinold, R.C. and Kahn, R.N. (2000) Active Portfolio Management. New York,
NY: McGraw-Hill.
Hartigan, J.A. (1975) Clustering algorithms. New York, NY: John Wiley &
Sons, Inc.
Hartigan, J.A. and Wong, M.A. (1979) Algorithm AS 136: A K-Means Clus-
tering Algorithm. Journal of the Royal Statistical Society, Series C (Applied
Statistics) 28(1): 100-108.
31
32
33
34
35
Level Min 1st Qu. Median Mean 3rd Qu. Max StDev MAD
1 87 93 94 93.95 96 99 2.33 1.48
2 20 24 25 24.93 26 28 1.91 1.48
3 6 8 9 8.58 9 10 0.93 1.48
Table 5: Simulation results for the optimized alphas with bounds using heterotic
risk models based on “top-down” 3-level statistical industry classifications obtained
via a single sampling in each run, with 3 runs for each choice of the 3-vector L eµ =
(L3 , L2 , L1 ), which is the reverse of the 3-vector Lµ , µ = 1, 2, 3, defined in Subsection
3.3.4. Also see Section 4 for details.
Run L
eµ ROC SR CPS
1 (10,5,5) 40.637% 16.502 2.055
2 (10,5,5) 40.880% 16.511 2.070
3 (10,5,5) 40.902% 16.684 2.075
1 (10,5,3) 41.278% 16.274 2.077
2 (10,5,3) 41.274% 16.342 2.076
3 (10,5,3) 41.044% 16.248 2.063
1 (10,3,4) 41.334% 16.046 2.071
2 (10,3,4) 41.442% 16.236 2.077
3 (10,3,4) 41.343% 16.130 2.071
1 (10,3,3) 41.590% 16.102 2.074
2 (10,3,3) 41.620% 16.029 2.072
3 (10,3,3) 41.654% 16.048 2.076
1 (10,2,3) 41.553% 15.724 2.054
2 (10,2,3) 42.046% 16.027 2.081
3 (10,2,3) 41.765% 15.665 2.066
1 (10,2,2) 42.144% 15.598 2.076
2 (10,2,2) 41.925% 15.516 2.063
3 (10,2,2) 42.007% 15.553 2.066
36
Run L
eµ ROC SR CPS
1 (10,5,5) 41.412% 16.550 2.098
2 (10,5,5) 41.478% 16.413 2.097
3 (10,5,5) 41.251% 16.401 2.092
1 (10,5,3) 41.696% 16.057 2.095
2 (10,5,3) 41.597% 16.157 2.093
3 (10,5,3) 41.730% 15.975 2.100
1 (10,3,4) 41.680% 15.979 2.085
2 (10,3,4) 41.643% 15.903 2.078
3 (10,3,4) 41.794% 16.023 2.092
1 (10,3,3) 42.078% 15.975 2.090
2 (10,3,3) 41.897% 15.962 2.083
3 (10,3,3) 41.785% 15.904 2.078
1 (10,2,3) 41.817% 15.618 2.063
2 (10,2,3) 41.964% 15.693 2.071
3 (10,2,3) 41.705% 15.598 2.062
1 (10,2,2) 42.080% 15.489 2.065
2 (10,2,2) 41.865% 15.433 2.059
3 (10,2,2) 41.987% 15.468 2.063
37
Table 8: Simulation results for the optimized alphas with bounds using heterotic
risk models based on “bottom-up” statistical industry classifications obtained via
aggregating 100 samplings in each run. K is the target number of clusters for a single
level. The K = 100 entry is the same as the last row in Table 2. See Subsection
3.3.3 and Section 4 for details. Also see Figures 1, 2 and 3.
K ROC SR CPS
10 41.726% 14.853 2.027
25 42.024% 15.395 2.065
50 42.180% 15.941 2.094
75 41.771% 16.115 2.085
100 41.775% 16.284 2.093
125 41.427% 16.205 2.080
150 41.306% 16.337 2.073
175 41.286% 16.456 2.076
200 40.774% 16.276 2.047
250 40.611% 16.248 2.032
38
Table 10: Simulation results (14 runs) for the optimized alphas with bounds using
heterotic risk models based on hybrid industry classifications (see Section 6) using
statistical industry classifications based on aggregating 100 samplings in each run.
39
Order Min 1st Qu. Median Mean 3rd Qu. Max StDev MAD
1 89 93 94 93.8 95 98 1.964 1.483
2 81 89 91 90.37 92 96 3.103 2.965
3 63 69 73 72.28 75 81 4.388 4.448
4 50 54 56 56.5 59 65 3.327 3.706
5 49 50 51 51.65 53 56 1.745 1.483
6 46 49 49 49.18 50 51 1.255 1.483
7 44 45.75 47 47.22 49 50 1.869 2.965
8 41 44 45.5 45.58 47 50 1.977 2.224
9 36 38.75 40 40.18 41 46 2.318 1.483
10 34 37 37 37.77 39 45 1.925 1.483
1 44 51.75 57 58.82 64 85 8.981 8.896
2 33 45 49 49 53.25 69 6.857 5.93
3 32 39.75 44 43.28 46.25 56 4.854 4.448
4 31 37 40 40.22 44 47 4.030 4.448
5 31 36 37 37.85 40.25 46 3.473 2.965
6 29 33.75 35 35.42 37 45 3.285 2.965
7 29 31.75 34 33.78 36 41 2.964 2.965
8 28 30 32 31.85 34 38 2.543 2.965
9 26 29 30.5 30.67 32.25 35 2.252 2.224
10 25 28 29 29.2 31 35 2.122 2.965
40
41.5
41.0
Cluster Number
Figure 1. Graph of the values of the return-on-capital (ROC) in percent from Table 8 vs.
the target number of clusters K (as defined in said table).
41
15.5
15.0
Cluster Number
Figure 2. Graph of the values of the Sharpe ratio (SR) from Table 8 vs. the target number
of clusters K (as defined in said table).
42
2.06
2.05
2.04
2.03
Cluster Number
Figure 3. Graph of the values of cents-per-share from Table 8 vs. the target number of
clusters K (as defined in said table).
43