-
Notifications
You must be signed in to change notification settings - Fork 98
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
ba87158
commit 74f20e8
Showing
8 changed files
with
287 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -39,3 +39,4 @@ Collate: | |
'ERM.R' | ||
'DVO.R' | ||
'OHV.R' | ||
'VCI.R' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,4 +16,5 @@ export(MSR) | |
export(ERM) | ||
export(OHV) | ||
export(DVO) | ||
export(VCI) | ||
export(agg.chart.ME) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
#'ValueCharts Indicator | ||
#'@description Computes a range-normalized difference between current price and a running moving average. | ||
#'A value below -8 indicates oversold, while a value above 8 indicates overbought. | ||
#'@param OHLC an OHLC time series | ||
#'@param nLookback a moving average window, default 40 | ||
#'@param nRange a lookback window for the range computation. A number above | ||
#'7 results in the following computation: take the difference between the nRange | ||
#'max high and min low. Add up that value, that value lagged by nRange+1, nRange*2, nRange*3, and nRange*4, | ||
#'and divide by 25. | ||
#'If nRange is 7 or less, the daily range is instead computed as the 5-day SMA of the following quantity: | ||
#'for each day, take the maximum of the difference between the high and low, or the absolute difference between current and previous close. | ||
#'Multiply that final quantity by .16. | ||
#'@return an OHLC-like 4-column output computing the values given OHLC prices, or a percent rank of the close variant. | ||
#'The column names will be VO, VH, VL, and VC, respectively. | ||
#'@references \url{http://www.tradesignalonline.com/en/lexicon/view.aspx?id=Value+Charts+Indicator} | ||
#'@export | ||
"VCI" <- function(OHLC, nLookback=40, nRange=8, pctRank=FALSE) { | ||
if(nLookback > 7) { | ||
varA <- runMax(Hi(OHLC), nRange) - runMin(Lo(OHLC), nRange) | ||
varB <- lag(varA, nRange+1) | ||
varC <- lag(varA, nRange*2) | ||
varD <- lag(varA, nRange*3) | ||
varE <- lag(varA, nRange*4) | ||
LRange <- (varA+varB+varC+varD+varE)/25 | ||
} | ||
if(nLookback <=7) { | ||
absDiff <- abs(diff(Cl(OHLC))) | ||
dailyRange <- Hi(OHLC) - Lo(OHLC) | ||
tmp <- cbind(absDiff, dailyRange) | ||
maxTmp <- pmax(tmp) | ||
LRange <- SMA(maxTmp, 5)*.16 | ||
} | ||
hilo <- (Hi(OHLC)+Lo(OHLC))/2 | ||
VO <- (Op(OHLC)-SMA(hilo, nLookback))/LRange | ||
VH <- (Hi(OHLC)-SMA(hilo, nLookback))/LRange | ||
VL <- (Lo(OHLC)-SMA(hilo, nLookback))/LRange | ||
VC <- (Cl(OHLC)-SMA(hilo, nLookback))/LRange | ||
out <- cbind(VO=VO, VH=VH, VL=VL, VC=VC) | ||
colnames(out) <- c("VO", "VH", "VL", "VC") | ||
return(out) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
require(IKTrading) | ||
require(quantstrat) | ||
require(PerformanceAnalytics) | ||
|
||
initDate="1990-01-01" | ||
from="2003-01-01" | ||
to=as.character(Sys.Date()) | ||
options(width=70) | ||
|
||
source("demoData.R") | ||
|
||
#trade sizing and initial equity settings | ||
tradeSize <- 100000 | ||
initEq <- tradeSize*length(symbols) | ||
|
||
strategy.st <- portfolio.st <- account.st <- "VCI_test" | ||
rm.strat(portfolio.st) | ||
rm.strat(strategy.st) | ||
initPortf(portfolio.st, symbols=symbols, initDate=initDate, currency='USD') | ||
initAcct(account.st, portfolios=portfolio.st, initDate=initDate, currency='USD',initEq=initEq) | ||
initOrders(portfolio.st, initDate=initDate) | ||
strategy(strategy.st, store=TRUE) | ||
|
||
#parameters | ||
pctATR=.02 | ||
period=10 | ||
|
||
nRange=2 | ||
nLookback=10 | ||
pctRank=FALSE | ||
|
||
buyThresh=-2 | ||
sellThresh=2 | ||
|
||
nSMA=200 | ||
|
||
#indicators | ||
add.indicator(strategy.st, name="lagATR", | ||
arguments=list(HLC=quote(HLC(mktdata)), n=period), | ||
label="atrX") | ||
|
||
add.indicator(strategy.st, name="VCI", | ||
arguments=list(OHLC=quote(OHLC(mktdata)), nLookback=nLookback, | ||
nRange=nRange, pctRank=pctRank), | ||
label="vci") | ||
|
||
add.indicator(strategy.st, name="SMA", | ||
arguments=list(x=quote(Cl(mktdata)), n=nSMA), | ||
label="sma") | ||
|
||
#signals | ||
add.signal(strategy.st, name="sigComparison", | ||
arguments=list(columns=c("Close", "SMA.sma"), relationship="gt"), | ||
label="filter") | ||
|
||
add.signal(strategy.st, name="sigThreshold", | ||
arguments=list(column="VC.vci", threshold=buyThresh, | ||
relationship="lt", cross=FALSE), | ||
label="VCIltThresh") | ||
|
||
add.signal(strategy.st, name="sigAND", | ||
arguments=list(columns=c("filter", "VCIltThresh"), cross=TRUE), | ||
label="longEntry") | ||
|
||
add.signal(strategy.st, name="sigThreshold", | ||
arguments=list(column="VC.vci", threshold=sellThresh, | ||
relationship="gt", cross=TRUE), | ||
label="longExit") | ||
|
||
add.signal(strategy.st, name="sigCrossover", | ||
arguments=list(columns=c("Close", "SMA.sma"), relationship="lt"), | ||
label="filterExit") | ||
|
||
#rules | ||
add.rule(strategy.st, name="ruleSignal", | ||
arguments=list(sigcol="longEntry", sigval=TRUE, ordertype="market", | ||
orderside="long", replace=FALSE, prefer="Open", osFUN=osDollarATR, | ||
tradeSize=tradeSize, pctATR=pctATR, atrMod="X"), | ||
type="enter", path.dep=TRUE) | ||
|
||
add.rule(strategy.st, name="ruleSignal", | ||
arguments=list(sigcol="longExit", sigval=TRUE, orderqty="all", ordertype="market", | ||
orderside="long", replace=FALSE, prefer="Open"), | ||
type="exit", path.dep=TRUE) | ||
|
||
add.rule(strategy.st, name="ruleSignal", | ||
arguments=list(sigcol="filterExit", sigval=TRUE, orderqty="all", ordertype="market", | ||
orderside="long", replace=FALSE, prefer="Open"), | ||
type="exit", path.dep=TRUE) | ||
|
||
#apply strategy | ||
t1 <- Sys.time() | ||
out <- applyStrategy(strategy=strategy.st,portfolios=portfolio.st) | ||
t2 <- Sys.time() | ||
print(t2-t1) | ||
|
||
#set up analytics | ||
updatePortf(portfolio.st) | ||
dateRange <- time(getPortfolio(portfolio.st)$summary)[-1] | ||
updateAcct(portfolio.st,dateRange) | ||
updateEndEq(account.st) | ||
|
||
|
||
#trade statistics | ||
tStats <- tradeStats(Portfolios = portfolio.st, use="trades", inclZeroDays=FALSE) | ||
tStats[,4:ncol(tStats)] <- round(tStats[,4:ncol(tStats)], 2) | ||
print(data.frame(t(tStats[,-c(1,2)]))) | ||
(aggPF <- sum(tStats$Gross.Profits)/-sum(tStats$Gross.Losses)) | ||
(aggCorrect <- mean(tStats$Percent.Positive)) | ||
(numTrades <- sum(tStats$Num.Trades)) | ||
(meanAvgWLR <- mean(tStats$Avg.WinLoss.Ratio[tStats$Avg.WinLoss.Ratio < Inf], na.rm=TRUE)) | ||
|
||
#daily and duration statistics | ||
dStats <- dailyStats(Portfolios = portfolio.st, use="Equity") | ||
rownames(dStats) <- gsub(".DailyEndEq","", rownames(dStats)) | ||
print(data.frame(t(dStats))) | ||
durStats <- durationStatistics(Portfolio=portfolio.st, Symbols=sort(symbols)) | ||
indivDurStats <- durationStatistics(Portfolio=portfolio.st, Symbols=sort(symbols), aggregate=FALSE) | ||
print(t(durStats)) | ||
print(t(indivDurStats)) | ||
|
||
#market exposure | ||
tmp <- list() | ||
length(tmp) <- length(symbols) | ||
for(i in 1:nrow(dStats)) { | ||
totalDays <- nrow(get(rownames(dStats)[i])) | ||
mktExposure <- dStats$Total.Days[i]/totalDays | ||
tmp[[i]] <- c(rownames(dStats)[i], round(mktExposure, 3)) | ||
} | ||
mktExposure <- data.frame(do.call(rbind, tmp)) | ||
colnames(mktExposure) <- c("Symbol","MktExposure") | ||
print(mktExposure) | ||
print(mean(as.numeric(as.character(mktExposure$MktExposure)))) | ||
|
||
#portfolio cash PL | ||
portString <- paste0("portfolio.", portfolio.st) | ||
portPL <- .blotter[[portString]]$summary$Net.Trading.PL | ||
|
||
#Cash Sharpe | ||
(SharpeRatio.annualized(portPL, geometric=FALSE)) | ||
|
||
#Portfolio comparisons to SPY | ||
instRets <- PortfReturns(account.st) | ||
|
||
#Correlations | ||
instCors <- cor(instRets) | ||
diag(instRets) <- NA | ||
corMeans <- rowMeans(instCors, na.rm=TRUE) | ||
names(corMeans) <- gsub(".DailyEndEq", "", names(corMeans)) | ||
print(round(corMeans,3)) | ||
mean(corMeans) | ||
|
||
portfRets <- xts(rowMeans(instRets)*ncol(instRets), order.by=index(instRets)) | ||
portfRets <- portfRets[!is.na(portfRets)] | ||
cumPortfRets <- cumprod(1+portfRets) | ||
firstNonZeroDay <- as.character(index(portfRets)[min(which(portfRets!=0))]) | ||
getSymbols("SPY", from=firstNonZeroDay, to=to) | ||
SPYrets <- diff(log(Cl(SPY)))[-1] | ||
cumSPYrets <- cumprod(1+SPYrets) | ||
comparison <- cbind(cumPortfRets, cumSPYrets) | ||
colnames(comparison) <- c("strategy", "SPY") | ||
chart.TimeSeries(comparison, legend.loc = "topleft", | ||
colors=c("green","red")) | ||
chart.RelativePerformance(portfRets,SPYrets) | ||
|
||
SharpeRatio.annualized(portfRets) | ||
Return.annualized(portfRets) | ||
maxDrawdown(portfRets) | ||
|
||
dailyRetComparison <- cbind(portfRets, SPYrets) | ||
colnames(dailyRetComparison) <- c("strategy", "SPY") | ||
round(apply.yearly(dailyRetComparison, Return.cumulative),3) | ||
round(apply.yearly(dailyRetComparison, SharpeRatio.annualized),3) | ||
round(apply.yearly(dailyRetComparison, maxDrawdown),3) | ||
|
||
chart.Posn(portfolio.st, "XLB") | ||
add_TA(SMA(Cl(XLB), n=nSMA), on=1, col="blue", lwd=2) | ||
vci <- VCI(OHLC(XLB), nRange=nRange, nLookback=nLookback, pctRank=pctRank) | ||
add_TA(vci$VC) | ||
add_TA(vci$VC - vci$VC + buyThresh, on=5, col="green") | ||
add_TA(vci$VC - vci$VC + sellThresh, on=5, col="red") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
\name{VCI} | ||
\alias{VCI} | ||
\title{ValueCharts Indicator} | ||
\usage{ | ||
VCI(OHLC, nLookback = 40, nRange = 8, pctRank = FALSE) | ||
} | ||
\arguments{ | ||
\item{OHLC}{an OHLC time series} | ||
|
||
\item{nLookback}{a moving average window, default 40} | ||
|
||
\item{nRange}{a lookback window for the range | ||
computation. A number above 7 results in the following | ||
computation: take the difference between the nRange max | ||
high and min low. Add up that value, that value lagged by | ||
nRange+1, nRange*2, nRange*3, and nRange*4, and divide by | ||
25. If nRange is 7 or less, the daily range is instead | ||
computed as the 5-day SMA of the following quantity: for | ||
each day, take the maximum of the difference between the | ||
high and low, or the absolute difference between current | ||
and previous close. Multiply that final quantity by .16.} | ||
} | ||
\value{ | ||
an OHLC-like 4-column output computing the values given | ||
OHLC prices, or a percent rank of the close variant. The | ||
column names will be VO, VH, VL, and VC, respectively. | ||
} | ||
\description{ | ||
Computes a range-normalized difference between current | ||
price and a running moving average. A value below -8 | ||
indicates oversold, while a value above 8 indicates | ||
overbought. | ||
} | ||
\references{ | ||
\url{http://www.tradesignalonline.com/en/lexicon/view.aspx?id=Value+Charts+Indicator} | ||
} | ||
|