Imaginary World

Why an imaginary world? the short answer is, because I studied economics and there I learnt to make assumptions whenever and wherever I desired :)). The long answer is that when I was backpacking through trans Siberia, I thought that in Tehran Stocks Exchange, short selling is not possible, as a result spread trading could not be exploited and hence spreads are high and mean revertible. Simply, if there is no competition, anomaly would preserve. So I thought if this is true, maybe one can detect with a plausible probability that which one of the pairs is undervalued, for example by utilizing a third or more series. And this could result in implementing nice strategies. Here I will see whether this assumption would result favorable results. Since it is an imaginary world I would use just simple methods. if it gonna work by using a third series, it need to be profitable in simple forms. For this purpose I tried to use QuantStrat package. Up until using it, I normally used functions written by myself for strategy implementation purposes. I used it, and it turned out to not be good idea, it was both slow and the code used different style than the packages I used. For example it used “match.names” function that used partial match names and it forced me to change all of my object naming method. Or some functions need to be modified to consider irregular dates format and NAs. I think that if I have had migrated to Julia for this matter it would have been better.

simple pair candidates

Pairs are selected based on correlations and not by common factor models. And the results where tested by Phillips Ouliaris test for cointegration. In of sample period from “2010-01-01” to “2015-01-01” has been used for computing correlations. I used whole sample data also, the results was profitable but I have not included them here. I mean, If I had the whole sample data, life would have not been a martingale :). The results are somehow strange and some pairs seems not to be related at all. Further, stocks are reduced to ones that have on average at least 5*10^5 volume per day. By my experience having this amount of volume, slippage could be neglected while trading 10^8 Rials value of stocks (it would be on average around 2-5 Rials per round trip trade on a normal day by my experience, a detailed an accurate quantity needs to be computed by tick data. In cases like the ones I explained in Markov Chain post, it would be substantially more. Here I have not seen that it is necessary to include such details). another reason is that I saw that less liquid assets have some lag before adjusting to news.

colnames(WDATA)<- c("DATE","sym","FIRST", "HIGH", "LOW", "LCLOSE",
                    "VOL", "CLOSE" )

vol.sym.mean<- ddply(WDATA, "sym", .fun = function(x) {
  denom<- as.numeric(x$DATE[dim(x)[1]] - x$DATE[1])
  denom<- floor(denom*(202/364))
  mean.vol<- sum(as.numeric(x$VOL), na.rm = TRUE) / denom
  return(mean.vol)
  })

sym.min.vol<- droplevels(vol.sym.mean[,1][which(vol.sym.mean[2] > 5*10^5)])
WDATA<-subset(WDATA, WDATA$sym %in% sym.min.vol)
WDATA<- droplevels(WDATA)

WDATA_last<- subset(WDATA_last, WDATA_last$DATE >= as.Date("2010-01-01") & WDATA_last$DATE <= as.Date("2015-01-01"))

retDATA<- WDATA_last[,c("DATE","sym","retCL_t")]
retDATAw<- dcast(retDATA, DATE ~ sym, value.var = "retCL_t")
J <- (retDATAw[, 1])
retDATAw <- retDATAw[,-1]
rownames(retDATAw)<- J
rm(J)
retDATAw<- apply(retDATAw,2, function(x) as.numeric(x))
#scale_retDATAw<- apply(retDATAw,2, scale)


abs_cor<- abs(cor(retDATAw, use = "pairwise.complete.obs"))
diag(abs_cor)<-0
cor.high.10<- sort(abs_cor, decreasing = TRUE)[1:50]

cor.ranked.sym<- list()
for( i in seq(2,50, by = 2)){
  cor.ranked.sym[[( i / 2)]]<-rownames(which(abs_cor == cor.high.10[i], arr.ind = TRUE))
}

for( i in 1 : length(cor.ranked.sym) ){
  ret.sym.1<- cor.ranked.sym[[i]][1]
  ret.sym.2<- cor.ranked.sym[[i]][2]
  ret.m<- cbind( retDATAw [ ,ret.sym.1 ], 
                 retDATAw [ ,ret.sym.2])
  temp<- po.test(ret.m)$p.value
  print(temp)
}

transaction costs

transaction costs is about 0.005 for buying the stock and 0.01 for selling the stocks. It also includes tax on selling stocks that is about 0.005 of stocks value. And a good point about Tehran Stock Exchange is that there is no other tax than this and capital gain tax is zero :)

txnFUN <- function(TxnQty, TxnPrice, Symbol, rate = 0.015) {
  comission <- abs(TxnQty) * TxnPrice * rate
  if (comission > 0) comission <- -comission
  return(comission)
}

Computing Spread

Total least square, Dynamic OLS, Integrated Modified OLS, and OLS with changing the dependent variable is used for getting the betas and constructing spread.

beta.fun<- function( ret.all = ret.m){
  
  
  end_date<- index(ret.all)[ length(ret.all[,1])]
  
  po.pvalue<- suppressWarnings( po.test(ret.all)$p.value)
  
  pca.ret<- prcomp( ~ as.numeric(ret.all[,1]) + as.numeric( ret.all[,2]))
  beta.pca<- pca.ret$rotation[2, 1] / pca.ret$rotation[1, 1]
  spread.pca<- ret.all[,2 ] - beta.pca * ret.all[,1 ]
  level.pca<- mean (spread.pca, na.rm = TRUE)
  
  beta.12<- lm(as.numeric(ret.all[,1])~as.numeric( ret.all[,2]) - 1)$coeff
  beta.21<- lm(as.numeric(ret.all[,2])~as.numeric( ret.all[,1]) - 1)$coeff
  spread.12<- ret.all[,1 ] - beta.12 * ret.all[,2 ]
  level.12<- mean (spread.12, na.rm = TRUE)
  spread.21<- ret.all[,2 ] - beta.21 * ret.all[,1 ]
  level.21<- mean (spread.21, na.rm = TRUE)
  
  beta.DOLS<- cointRegD(as.numeric( ret.all[,1]), as.numeric( ret.all[,2]))$beta
  spread.DOLS<- ret.all[,1 ] - beta.DOLS * ret.all[,2 ]
  level.DOLS<- mean (spread.DOLS, na.rm = TRUE)
  
  beta.IMOLS<- cointRegIM(as.numeric( ret.all[,1]), as.numeric( ret.all[,2]))$gamma
  spread.IMOLS<- ret.all[,1 ] - beta.IMOLS * ret.all[,2 ]
  level.IMOLS<- mean (spread.IMOLS, na.rm = TRUE)
  
  out<- cbind.data.frame(#DATE = end_date,
    po.pvalue = po.pvalue,
    beta.pca = beta.pca,
    spread.pca = spread.pca[length(spread.pca)],
    level.pca = level.pca,
    beta.12 = beta.12,
    spread.12 = spread.12[length(spread.12)],
    level.12 = level.12,
    beta.21 = beta.21,
    spread.21 = spread.21[length(spread.21)],
    level.21 = level.21,
    beta.DOLS = beta.DOLS,
    spread.DOLS = spread.DOLS[length(spread.DOLS)],
    level.DOLS = level.DOLS,
    beta.IMOLS = beta.IMOLS,
    spread.IMOLS = spread.IMOLS[length(spread.IMOLS)],
    level.IMOLS = level.IMOLS
    # po.test, if needed for furthure work
  )
  out<- as.numeric(out)
  return(out)
}

thresold_level<- function(data = data ,level.m = "mlevel_pca", sd.m = "sd_spread_pca", multi = 1) {
  sym.name<- strsplit(colnames(data)[1], split="[.]")[[1]][1]
  out<- cbind( data[, level.m] + (multi * data[, sd.m]),
               data[, level.m] - (multi * data[, sd.m]))
  method.name<- strsplit(level.m, split="[_]")[[1]][2]
  names.out<- c( paste("upper", method.name, sep = "_"),
                 paste("lower", method.name, sep = "_"))
  colnames(out)<- names.out
  return(out)
}

The threshold is computed based on standard deviation of spread.

Function for placing orders

This function is a modification to demo function in the package that I modified for replacing pairs order, NAs in data and considering end equity on trade size. I use level one for trade sizing, tests with level two resulted on much better results.

osSpreadMaxPos <- function (data, timestamp, orderqty, ordertype, orderside, beta.method, lvls,
                            portfolio.st, account.st,
                            portfolio, symbol, ruletype, reverse, cor.pair, orderprice, ...) {
  portf <- getPortfolio(portfolio)
  #check to make sure pair slot has the things needed for this function
  
  x<- get(symbol)$RHS[1]
  if (x == 1) legside <- "long"
  if (x == 0) legside <- "short"
  if (reverse == TRUE & x == 1) legside <- "short"
  if (reverse == TRUE & x == 0) legside <- "long"
  
  updatePortf(portfolio.st)
  updateAcct( account.st, paste(t.out0, timestamp, sep="::"))
  updateEndEq( account.st, paste(t.out0, timestamp, sep="::"))
  endEq<- floor( getEndEq( account.st, Date = timestamp))
  
  
  x1 <- get(cor.pair[1])
  x2 <- get(cor.pair[2])
  
  spread.price <- (1 * Cl(x1)) + (abs(x1[,beta.method]) * Cl(x2))
  if (reverse == TRUE){
    spread.price <- (abs(x1[,beta.method]) * Cl(x1)) + ( 1 * Cl(x2))
  }
  colnames(spread.price) <- 'spread.price'
  
  spread.num<- endEq / spread.price
  
  long.size<- (spread.num / (1 + abs(x1[,beta.method]))) / (lvls )
  short.size<- (long.size * abs(x1[,beta.method])) / (lvls)
  
  long.size[ is.na(long.size)]<- 0
  short.size[ is.na(short.size)]<- 0
  long.size[ is.null(long.size)]<- 0
  short.size[ is.null(short.size)]<- 0
  if( length(x1[as.POSIXct(timestamp)]) != 0 & 
      length(long.size[as.POSIXct(timestamp)]) != 0 &
      length(short.size[as.POSIXct(timestamp)]) != 0) {
  #ratio <- getHedgeRatio(portfolio, timestamp)
  pos <- getPosQty(portfolio, symbol, timestamp)
  try(addPosLimit(portfolio=portfolio, timestamp=timestamp, symbol=symbol,
                  maxpos=round(long.size[as.POSIXct(timestamp)],0), longlevels=lvls,
                  minpos=round(-long.size[as.POSIXct(timestamp)],0), shortlevels=lvls))
  qty <- long.size[as.POSIXct(timestamp)] 
  if (legside == "short") {#symbol is 2nd leg
    ## Comment out next line to use equal ordersizes for each stock.
    try(addPosLimit(portfolio=portfolio, timestamp=timestamp, symbol=symbol,
                    maxpos=round(short.size[as.POSIXct(timestamp)],0), longlevels=lvls,
                    minpos=round(-short.size[as.POSIXct(timestamp)],0), shortlevels=lvls))
    ##
    qty <- -short.size[as.POSIXct(timestamp)]  #switch orderqty for Stock B
  }
  
  if (qty > 0) orderside = 'long'
  if (qty < 0) orderside = 'short'
  
  orderqty <- osMaxPos(data=data,timestamp=timestamp, orderqty=qty,
                       ordertype=ordertype, orderside=orderside,
                       portfolio=portfolio, symbol=symbol, ruletype=ruletype,
                       ...)
  
  } else {
    qty <- 0
    orderside <- 'long'
    orderqty <- 0
  }
  
  if (!is.null(orderqty) & !orderqty == 0 & !is.null(orderprice)) {
    addOrder(portfolio=portfolio, symbol=symbol,
             timestamp=timestamp, qty=orderqty, price=as.numeric(orderprice),
             ordertype=ordertype, side=orderside, replace=FALSE,
             status="open", ...=...)
  }
  return(0) 
}

Loop or Function

First I tried to write a function for computing the results but some of packages functions failed to work inside functions, I think it was because of environment they were defined to create. Instead of making changes in global environment with functions, I see that it is more reasonable to use for loops. Here I do not write replication for different kind of calculated spread and corresponding rules and signals- it became too lengthy. Betas, Spread level and sd are computed by 30 days backward rolling window.

results<- list()
temp<- NULL
for ( i in 6 : length(cor.ranked.sym)){

  cor.pair = cor.ranked.sym [[i]]
  beta.fun. = beta.fun;
  osSpreadMaxPos. = osSpreadMaxPos # index = VLGI
  txnFUN. = txnFUN
    
    rm(list = ls(.blotter), envir = .blotter)
    rm(list = ls(.strategy), envir = .blotter)
    if (!exists('.blotter')) .blotter <- new.env()
    if(!exists('.strategy')) .strategy <- new.env()
    if(!exists('.instrument')) .instrument <- new.env()
    
    symbols <- cor.pair
    stock(symbols, currency = "IRR", multiplier = 1)
    ret.1<- diff.xts( x = log( get( cor.pair[1 ])[,6 ]))
    ret.2<- diff( log( get( cor.pair[2 ])[,6 ]))
    ret.m<- cbind( ret.1, ret.2)
    ret.m<- ret.m[complete.cases(ret.m[,1]),]
    ret.m<- ret.m[complete.cases(ret.m[,2]),]
    ret.m<- ret.m[paste(t.out0,"::", sep = "")]
    
    # roll apply
    
    betas<- rollapply(ret.m, width = 30,
                      FUN = function(x) beta.fun.(x), by.column = FALSE, align = "right")
    sd_spread<- rollapply(betas[,c(3,6,9,12,15)],
                          width = 30, FUN = function(x) apply(x, 2 , sd, na.rm = TRUE),
                          by.column = FALSE, align = "right")
    mean_level<- rollapply(betas[,c(4,7,10,13,16)],
                           width = 30, FUN = function(x) apply(x, 2 , sd, na.rm = TRUE),
                           by.column = FALSE, align = "right")
    betas<- cbind(betas, sd_spread)
    betas<- cbind( betas, mean_level)
    
    names_beta<- c("po_pvalue", "beta_pca", "spread_pca",
                   "level_pca", "beta_12", "spread_12",
                   "level_12", "beta_21", "spread_21",
                   "level_21", "beta_DOLS", "spread_DOLS",
                   "level_DOLS", "beta_IMOLS", "spread_IMOLS",
                   "level_IMOLS",
                   "sdD_pca", "sdD_12", "sdD_21",
                   "sdD_DOLS", "sdD_IMOLS",
                   "mlevel_pca", "mlevel_12", "mlevel_21",
                   "mlevel_DOLS", "mlevel_IMOLS")
    colnames(betas)<- names_beta
    
    #zero crossing
    zerocross.pca<- length( rle( as.numeric(betas$spread_pca) >=
                                   as.numeric(betas$mlevel_pca))$lengths) -1
    zerocross.12<- length( rle( as.numeric(betas$spread_12) >= 
                                  as.numeric(betas$mlevel_12))$lengths) -1
    zerocross.21<- length( rle( as.numeric(betas$spread_21) >=
                                  as.numeric(betas$mlevel_21))$lengths) -1
    zerocross.DOLS<- length( rle( as.numeric(betas$spread_DOLS) >=
                                    as.numeric(betas$mlevel_DOLS))$lengths) -1
    zerocross.IMOLS<- length( rle( as.numeric(betas$spread_IMOLS) >=
                                     as.numeric(betas$mlevel_IMOLS))$lengths) -1
    
    zerocross<- c( zerocross.pca = zerocross.pca, zerocross.12 = zerocross.12,
                   zerocross.21 = zerocross.21, zerocross.DOLS = zerocross.DOLS,
                   zerocross.IMOLS = zerocross.IMOLS)
    
    
    sd.pca<- thresold_level( data = betas,
                             level.m = "mlevel_pca", sd.m = "sdD_pca", multi = 1)
    betas<- cbind( betas, sd.pca)
    
### doing same for other methods
    
    
    temp<- get( cor.pair[1 ])
    temp<- cbind( temp, betas)
    temp<- cbind( temp, 1)
    colnames( temp)[ length( colnames( temp))]<- "RHS"
    assign( cor.pair[1 ], temp)
    rm( temp)
    
    
    temp<- get( cor.pair[2 ])
    temp<- cbind( temp, betas)
    temp<- cbind( temp, 0)
    colnames( temp)[ length( colnames( temp))]<- "RHS"
    assign( cor.pair[2 ], temp)
    rm( temp)
    
    # buy sell signal
    
    strategy.pca <- paste("strategy", "pca",  cor.pair[1 ],  cor.pair[2 ], sep = "_")
    portfolio.pca <- paste("portfolio", "pca",  cor.pair[1 ],  cor.pair[2 ], sep = "_")
    account.pca<- paste("account", "pca",  cor.pair[1 ],  cor.pair[2 ], sep = "_")
    rm.strat(portfolio.pca)
    rm.strat(strategy.pca)
    rm.strat(account.pca)
    
    initPortf( portfolio.pca, symbols = symbols, initDate = initDate, currency = "IRR")
    initAcct( account.pca, portfolios = portfolio.pca, initDate = initDate, currency = "IRR", initEq = initEq)
    initOrders(portfolio =  portfolio.pca, initDate = initDate)
    #test<- tryCatch(getPortfolio(portfolio.pca), error=function(e){NA})
    strategy(strategy.pca, store = TRUE)
    
    # same for other methods

    add.signal(strategy = strategy.pca,  data = quote(mktdata), name = "sigCrossover",
               arguments = list( columns = c( "spread_pca", "upper_pca"), relationship= "gt"),
               label = "shortOrsell")
    
    add.signal(strategy = strategy.pca, data = quote(mktdata), name = "sigCrossover",
               arguments = list( columns = c( "spread_pca", "lower_pca"), relationship= "lt"),
               label = "buyOrcover")
    
    # same for other methods
    #### pca
    
    add.rule(strategy=strategy.pca, name='ruleSignal',
             arguments=list(sigcol="shortOrsell", sigval=TRUE,
                            orderqty=1e7, ordertype='market', cor.pair = cor.pair,
                            orderside=NULL, osFUN='osSpreadMaxPos.',  reverse = FALSE,
                            replace = FALSE,  beta.method = "beta_pca",lvls = 1,
                            portfolio.st = portfolio.pca,
                            account.st = account.pca,
                            TxnFees = "txnFUN.", rate = 0.01,
                            prefer = "Open"),
             type='enter')
    add.rule(strategy=strategy.pca, name='ruleSignal',
             arguments=list(sigcol="buyOrcover", sigval=TRUE,
                            orderqty=-1e7, ordertype='market', cor.pair= cor.pair,
                            orderside=NULL, osFUN='osSpreadMaxPos.', reverse = FALSE,
                            replace = FALSE,  beta.method = "beta_pca",lvls = 1,
                            portfolio.st = portfolio.pca,
                            account.st = account.pca,
                            TxnFees = "txnFUN.", rate = 0.005,
                            prefer = "Open"),
             type='enter')
    add.rule(strategy=strategy.pca, name='ruleSignal',
             arguments=list(sigcol="buyOrcover", sigval=TRUE,
                            orderqty='all', ordertype='market',
                            orderside=NULL, 
                            replace = FALSE,
                            TxnFees = "txnFUN.", rate = 0.005,
                            prefer = "Open"),
             type='exit')
    add.rule(strategy=strategy.pca, name='ruleSignal',
             arguments=list(sigcol="shortOrsell", sigval=TRUE,
                            orderqty='all', ordertype='market',
                            orderside=NULL, 
                            replace = FALSE,
                            TxnFees = "txnFUN.", rate = 0.01,
                            prefer = "Open"),
             type='exit')
    
    # same for other methods
    
    ######
    
    ###############
    applyStrategy(strategy.pca, portfolio.pca, debug = TRUE)
    updatePortf(portfolio.pca)
    updateAcct( account.pca,paste(t.out0, t.out1, sep="::"))
    updateEndEq(account.pca, paste(t.out0, t.out1, sep="::"))
    
    # same for other methods
    
    ###########
    
    ret1 <- PortfReturns(account.pca,
                         Dates = paste(t.out0, t.out1, sep="::"))[paste(t.out0, t.out1, sep="::")]
    PortRets.pca <- xts(rowSums(ret1) , order.by = index(ret1))
    
    # same for other methods
    
    mDraw.pca<- maxDrawdown( PortRets.pca)
    an.ret.pca<- as.numeric( Return.annualized( PortRets.pca, geometric = TRUE))
    an.sharp.pca<- as.numeric( SharpeRatio.annualized(PortRets.pca))
    UPR.pca<- as.numeric( UpsidePotentialRatio( PortRets.pca)) 
    #InformationRatio(Ra, VLGI, scale = NA)
    #UpDownRatios
    
    # same for other methods
    
    out<- list( ret = list( PortRets.pca = PortRets.pca,
                            PortRets.12 = PortRets.12,
                            PortRets.21 = PortRets.21,
                            PortRets.DOLS = PortRets.DOLS,
                            PortRets.IMOLS = PortRets.IMOLS),
                zerocross = zerocross,
                mDraw = c( mDraw.pca, mDraw.12,
                           mDraw.21, mDraw.DOLS,
                           mDraw.IMOLS),
                an.ret = c( an.ret.pca, an.ret.12,
                            an.ret.21, an.ret.DOLS,
                            an.ret.IMOLS),
                an.sharp = c( an.sharp.pca, an.sharp.12,
                              an.sharp.21, an.sharp.DOLS,
                              an.sharp.IMOLS),
                UPR = c( UPR.pca, UPR.12,
                         UPR.21, UPR.DOLS,
                         UPR.IMOLS))
  results[[i]]<- out
 print(i)
}

Results

for comparing strategies I usually use annualized returns, max drawdown and Sharp ratio. The first one tells me whether it is better than GDP deflator and VLGI, the second tells me whether I can take the pain, and third one compares it with risk defined as variance. Usually other measures for risk adjusted returns are used, but before I was thinking that if stop losses are not existed in strategy, then if we take out the drift term, whatever could happen upward could happen downward also. I mean, one cannot simply neglect upward movements of a martingale, just because it is plausible for them or compare a Brownian motion with another and their comovement, and consider it highly informative; the information has already been shown through correlation and Beta, plus drift. After I read this I just dropped the assumption that absence of stop loss is necessary, since it says that it is the case even for truncated elliptical distributions.

path = "C:/Users/msdeb/Documents/Stock and trades/"
setwd(path)
load(".Rdata")
library(pander)

an.ret<- NULL
temp<- NULL
an.sharp<- NULL
mDraw<- NULL
UPR<- NULL 
zerocross<- NULL

for ( i in 1 : length( results)){
  temp <- results[[i]]$an.ret
  an.ret <- rbind( an.ret, temp)
  temp <- results[[i]]$an.sharp
  an.sharp <- rbind( an.sharp, temp)
  temp <- results[[i]]$mDraw
  mDraw <- rbind( mDraw, temp)
  temp <- results[[i]]$UPR
  UPR <- rbind( UPR, temp)
  temp <- results[[i]]$zerocross
  zerocross <- rbind( zerocross, temp)
  
  name<- paste(cor.ranked.sym [[i]][1 ],  cor.ranked.sym [[i]][2 ], sep = "_")
  rownames(an.ret)[i]<- name
  rownames(an.sharp)[i]<- name
  rownames(mDraw)[i]<- name
  rownames(UPR)[i]<- name
  rownames(zerocross)[i]<- name
}
name<- c( "pca", "12", "21", "DOLS", "IMOLS")
  colnames(an.ret)<- name
  colnames(an.sharp)<- name
  colnames(mDraw)<- name
  colnames(UPR)<- name
  colnames(zerocross)<- name

pander(an.ret)
  pca 12 21 DOLS IMOLS
MSKN_DADE -0.1191 -0.1576 -0.0954 -0.1847 -0.175
PETR_KAVR -0.03679 -0.132 -0.2176 -0.136 -0.08305
SPDZ_SAHD -0.2066 -0.1332 -0.1305 -0.1787 -0.1033
TOKA_SPDZ -0.0907 -0.1271 -0.1402 -0.1833 -0.1811
TOKA_SAHD -0.1233 -0.1074 -0.1647 -0.1271 -0.1415
TRIR_DADE -0.1022 -0.09237 -0.06199 -0.1722 -0.1815
SPDZ_MADN -0.1492 -0.1821 -0.1497 -0.2017 -0.09106
CHML_BMDZ -0.02405 -0.02676 -0.1791 -0.105 -0.05954
SAHD_PLKK -0.1315 -0.1382 -0.1497 -0.1236 -0.104
TRIR_MSKN -0.03885 -0.1406 -0.1162 -0.1159 -0.2215
KRAF_BHKZ -0.01496 0.01845 -0.2321 -0.1935 -0.09654
SPDZ_BIME -0.1993 -0.1532 0.01241 -0.2255 -0.1326
TOKA_PLKK -0.1344 -0.1602 -0.1382 -0.157 -0.1386
CHML_BSTE -0.04435 -0.03258 -0.1499 -0.1137 -0.1293
SPDZ_PLKK -0.1933 -0.1769 -0.1514 -0.1932 -0.1228
TRIR_BHKZ -0.0053 -0.1206 -0.197 0.0105 -0.03681
TOKA_MADN -0.03911 -0.1897 -0.107 -0.1403 -0.126
SSHR_AZIN -0.05137 -0.2715 -0.1157 -0.1752 -0.196
SPDZ_BANK -0.2575 -0.1372 -0.09012 -0.2419 -0.2177
SPDZ_COMB -0.1907 -0.03624 -0.1892 -0.1657 -0.1745
HPKP_BHKZ -0.0542 -0.1469 -0.2615 -0.1798 -0.1569
TORZ_BGHZ -0.1574 -0.09773 -0.2016 -0.1101 -0.1561
TRIR_KRAF -0.06131 -0.2012 -0.06416 -0.1071 -0.1113
MSKN_BHKZ -0.03129 -0.05945 -0.2585 -0.06324 -0.09587
TOKA_COMB -0.1278 -0.1374 -0.2291 -0.06743 -0.1591
pander(colMeans(an.ret))
pca 12 21 DOLS IMOLS
-0.1034 -0.1256 -0.1511 -0.1461 -0.1357
pander(an.sharp)
  pca 12 21 DOLS IMOLS
MSKN_DADE -1.493 -2.378 -0.4827 -2.623 -2.483
PETR_KAVR -0.5154 -0.8825 -1.779 -0.9855 -0.7885
SPDZ_SAHD -2.074 -1.124 -1.04 -1.16 -0.5504
TOKA_SPDZ -1.468 -0.4212 -1.675 -0.8586 -1.018
TOKA_SAHD -2.399 -0.7916 -1.576 -1.16 -1.245
TRIR_DADE -0.8033 -0.8603 -0.3515 -1.137 -1.746
SPDZ_MADN -1.235 -1.505 -1.154 -1.254 -0.4263
CHML_BMDZ -0.5748 -0.1282 -1.4 -0.6869 -0.5226
SAHD_PLKK -2.337 -2.007 -0.65 -2.506 -2.542
TRIR_MSKN -0.297 -1.146 -0.9144 -0.6997 -2.294
KRAF_BHKZ -0.6621 0.08135 -2.243 -1.457 -1.028
SPDZ_BIME -1.808 -1.329 0.06908 -1.677 -0.7211
TOKA_PLKK -2.451 -1.272 -1.108 -1.279 -1.156
CHML_BSTE -0.9839 -0.16 -0.9741 -0.9615 -1.804
SPDZ_PLKK -1.772 -1.493 -1.118 -1.376 -0.6714
TRIR_BHKZ -0.03859 -0.9577 -2.046 0.05516 -0.3142
TOKA_MADN -0.6652 -1.449 -0.9134 -1.182 -1.082
SSHR_AZIN -1.074 -1.6 -0.3651 -1.088 -1.265
SPDZ_BANK -2.784 -1.095 -0.8336 -2.157 -1.156
SPDZ_COMB -1.751 -0.2111 -1.692 -1.013 -0.7581
HPKP_BHKZ -0.1895 -1.231 -2.473 -1.049 -0.7433
TORZ_BGHZ -2.146 -0.7947 -1.823 -0.8831 -1.237
TRIR_KRAF -0.2067 -1.124 -1.665 -0.3986 -0.3801
MSKN_BHKZ -0.5748 -1.141 -1.844 -1.25 -1.753
TOKA_COMB -2.584 -1.031 -2.292 -0.4901 -1.595
pander(colMeans(an.sharp))
pca 12 21 DOLS IMOLS
-1.315 -1.042 -1.294 -1.171 -1.171
pander(mDraw)
  pca 12 21 DOLS IMOLS
MSKN_DADE 0.2789 0.3671 0.4138 0.3967 0.3755
PETR_KAVR 0.1793 0.3617 0.4567 0.4037 0.2511
SPDZ_SAHD 0.4403 0.3156 0.3863 0.4205 0.3578
TOKA_SPDZ 0.1986 0.5156 0.3159 0.4399 0.4006
TOKA_SAHD 0.282 0.283 0.4208 0.3437 0.3221
TRIR_DADE 0.2784 0.2638 0.3188 0.4852 0.3992
SPDZ_MADN 0.3406 0.4062 0.3328 0.4447 0.4158
CHML_BMDZ 0.07467 0.2817 0.3886 0.3145 0.2475
SAHD_PLKK 0.2931 0.3197 0.4386 0.2892 0.2486
TRIR_MSKN 0.1878 0.351 0.2876 0.4178 0.4631
KRAF_BHKZ 0.04448 0.3062 0.4751 0.4103 0.241
SPDZ_BIME 0.4283 0.378 0.4016 0.4799 0.3961
TOKA_PLKK 0.3177 0.4282 0.3309 0.4117 0.3253
CHML_BSTE 0.112 0.2647 0.3444 0.3167 0.3032
SPDZ_PLKK 0.4161 0.5046 0.3598 0.4593 0.322
TRIR_BHKZ 0.1818 0.3138 0.4168 0.2669 0.3103
TOKA_MADN 0.1216 0.4248 0.2438 0.3445 0.3067
SSHR_AZIN 0.1298 0.5659 0.3911 0.4373 0.4024
SPDZ_BANK 0.5147 0.3888 0.3074 0.5018 0.4568
SPDZ_COMB 0.4126 0.3378 0.4007 0.4031 0.4909
HPKP_BHKZ 0.2917 0.3659 0.5302 0.4069 0.411
TORZ_BGHZ 0.3651 0.3376 0.4483 0.3655 0.4021
TRIR_KRAF 0.4259 0.4485 0.1548 0.4595 0.4244
MSKN_BHKZ 0.07956 0.1547 0.5471 0.1523 0.2187
TOKA_COMB 0.2974 0.3522 0.4789 0.2157 0.3648
pander(colMeans(mDraw))
pca 12 21 DOLS IMOLS
0.2677 0.3615 0.3836 0.3835 0.3543
pander(UPR)
  pca 12 21 DOLS IMOLS
MSKN_DADE 0.5455 0.3821 0.9347 0.3742 0.4338
PETR_KAVR 0.7307 0.7676 0.6951 0.8132 0.6747
SPDZ_SAHD 0.4583 0.6584 0.8653 0.5329 0.6946
TOKA_SPDZ 0.6109 0.7675 0.5703 0.7897 0.7353
TOKA_SAHD 0.5242 0.8107 0.7898 0.8151 0.6241
TRIR_DADE 0.6442 0.7448 0.838 0.7792 0.6542
SPDZ_MADN 0.6146 0.4904 0.8401 0.5226 0.6238
CHML_BMDZ 0.4323 0.8916 0.732 0.7125 0.7693
SAHD_PLKK 0.5435 0.5619 0.8268 0.4784 0.4136
TRIR_MSKN 0.5945 0.5636 0.7593 0.6129 0.4325
KRAF_BHKZ 0.4044 0.7102 0.5377 0.55 0.437
SPDZ_BIME 0.6229 0.7504 0.9058 0.6406 0.7573
TOKA_PLKK 0.6079 0.687 0.8114 0.8254 0.6386
CHML_BSTE 0.3633 0.6992 0.7413 0.6843 0.596
SPDZ_PLKK 0.5079 0.6039 0.7131 0.5327 0.6544
TRIR_BHKZ 0.665 0.568 0.5063 0.7001 0.6707
TOKA_MADN 0.6713 0.6942 0.8158 0.6011 0.6285
SSHR_AZIN 0.2865 0.4789 0.6822 0.7088 0.3111
SPDZ_BANK 0.5062 0.5941 0.802 0.6959 0.557
SPDZ_COMB 0.5231 0.5202 0.8103 0.6109 0.5333
HPKP_BHKZ 0.7173 0.5855 0.4523 0.6834 0.6816
TORZ_BGHZ 0.5695 0.8284 0.694 0.7353 0.7213
TRIR_KRAF 0.7264 0.6139 0.4446 0.7623 0.7992
MSKN_BHKZ 0.549 0.4921 0.825 0.5087 0.4751
TOKA_COMB 0.4789 0.7741 0.705 0.8321 0.7183
pander(colMeans(UPR))
pca 12 21 DOLS IMOLS
0.5559 0.6496 0.7319 0.6601 0.6094
#pander(zerocross)
pander(colMeans(zerocross))
pca 12 21 DOLS IMOLS
214.6 220.9 230 225.2 217.4

Conclusion

The results shows that the strategies are not profitable, so I leave this idea and I would not proceed for improving it. It it was supposed to be good it should have shown that in simplest form.

Further total least square and after that IM OLS showed better results than others. The case that IM OLS works better than simple OLS was not a straightforward conclusion for me, because it uses hyper parameters and by my experience this would usually make things worse, which was not the case here.

Please inform me about your feedback, I will be deeply grateful for that :)
For disclaimer please see about page.