(我知道这是一个冗长而混乱的问题,但我真的希望有人能帮助我,因为我已经研究这个看似简单的东西大约两个星期了......)
两个问题
1) 在 quantstrat 中,我找到了可用于重新平衡投资组合的函数rulePctEquity 。当我阅读这个函数里面的代码时,我发现这个函数主要是关于有一个新的addPosLimit。我可以知道将 add.rule(qs.strategy, 'rulePctEquity',...) 理解为设置检查其他规则的频率和进入的最大位置的工具是否正确?换句话说,如果这是策略中的唯一规则,是否意味着不会进行交易?
2)在展示我的代码之前,我的测试策略总结如下。在每个月初,投资组合将出售其拥有的所有股票并购买当时排名前 3 位(排名)的精选股票。使用等重进行测试。
但是,我的测试结果与我认为应该显示的结果大不相同。为了节省时间,我认为问题出在第 4 节。指示买、卖空、卖和买覆盖的功能
library(quantstrat)
library(lattice)
quotes.file <- "testfile.csv" #Need editing
quotes.file2 <- "testfile2.csv" #Need editing
#
# 1. Instrument: read csv file into xts object
#
code <- read.csv(quotes.file2,head=TRUE)
data2 <- read.csv(quotes.file, head=TRUE)
code=apply(code,1,"toString")
matsplitter<-function(M, r, c) {
rg <- (row(M)-1)%/%r+1
cg <- (col(M)-1)%/%c+1
rci <- (rg-1)*max(cg) + cg
N <- prod(dim(M))/r/c
cv <- unlist(lapply(1:N, function(x) M[rci==x]))
dim(cv)<-c(r,c,N)
cv
}
data=matsplitter(data2[,-1],nrow(data2),4)
colnames(data)=c("close","pe","pe_avg","pe_sd")
dates <- as.Date(data2$Date,"%d/%m/%Y")
C=list()
i=1
for (i in 1:(dim(data)[3])){
C[[i]] <- xts(x=data[,,i], order.by=dates)
}
#
# 2. Support Functions
#
osFixedDollar <- function(timestamp,orderqty, portfolio, symbol, ruletype, ...)
{
ClosePrice <- as.numeric((mktdata[timestamp,"close"]))
orderqty <- round(tradeSize/ClosePrice,-2)
return(orderqty)
}
pause <- function() {
cat ("Press [enter] to continue")
line <- readline()
}
Zscore <- function(x0,y0,z0) {
x <- as.numeric(x0)
y <- as.numeric(y0)
z <- as.numeric(z0)
res <- (x-y)/z
res
}
for (i in 1:(dim(data)[3])){
C[[i]]$Zscore <-Zscore(C[[i]]$pe,C[[i]]$pe_avg,C[[i]]$pe_sd)
}
for (j in 1:(nrow(data))){
temp=0
for (i in 1:(dim(data)[3])){
temp=c(temp,C[[i]][j,"Zscore"])
}
temp=temp[-1]
temp=as.numeric(temp)
temp2=rank(temp)
for (i in 1:(dim(data)[3])){
C[[i]]$ranking[j]=temp2[i]
}
}
for (i in 1:(dim(data)[3])){
assign(code[i],C[[i]])
}
#
# 3. Initializations
#
# Currency:
currency("HKD")
# Instrument:
big.point.value <- 1
for (i in 1:(dim(data)[3])){
stock(code[i], currency="HKD", multiplier=big.point.value)
}
# Strategy, portfolio and account names:
qs.strategy <- "PE.on.HKex"
qs.portfolio <- "Equities"
qs.account <- "My.account"
# Remove previous strategy, portfolio and account:
suppressWarnings(rm(list = c(paste("account", qs.account, sep='.'), paste("portfolio", qs.portfolio, sep='.')), pos=.blotter))
suppressWarnings(rm(list = c(qs.strategy, paste("order_book", qs.portfolio, sep='.')), pos=.strategy))
rm.strat(qs.strategy) # remove strategy etc. if this is a re-run
# Portfolio:
initDate <- '2015-01-01'
initPortf(qs.portfolio, code, initDate=initDate, currency='HKD')
# Account:
initEq <- 100000
initAcct(qs.account, portfolios=qs.portfolio, initDate=initDate, currency='HKD', initEq=initEq)
# Orders:
initOrders(portfolio=qs.portfolio, initDate=initDate)
# Strategy:
strategy(qs.strategy, store=TRUE)
#
# 4. Functions indicating buy, sell short, sell and buy to cover
#
nb.bars.with.no.trade <- 0
topchoice=3
buy.function <- function(x) {
N <- nrow(x)
buy.signals <- numeric(N)
# buy.signals[1:nb.bars.with.no.trade]<- 0
for (i in (nb.bars.with.no.trade+1):N) {
if ( (x[i]<=topchoice)
&& (index(x)[i] < index(get(code[1]))[nrow(data)]) # trick to avoid an open trade at the end
) {
buy.signals[i] <- 1
} else {
buy.signals[i] <- 0
}
}
xts(x=buy.signals, order.by=index(x))
}
sell.function <- function(x) {
N <- nrow(x)
sell.signals <- numeric(N)
#sell.signals[1:nb.bars.with.no.trade]<- 0
for (i in (nb.bars.with.no.trade+1):N) {
#if ( (x[i]<=topchoice) && (index(x)[i] < index(get(code[1]))[nrow(data)])){
# sell.signals[i] <- 0}
#else{
sell.signals[i] <-1
#}
}
xts(x=sell.signals, order.by=index(x))
}
#
# 5. Indicators for buy, sell short, sell and buy to cover
#
add.indicator(strategy = qs.strategy,
name = "buy.function",
arguments = list(x = quote(mktdata[,"ranking"])),
label="Buy")
add.indicator(strategy = qs.strategy,
name = "sell.function",
arguments = list(x = quote(mktdata[,"ranking"])),
label="Sell")
#
# 6. Signals for buy, sell short, sell and buy to cover
#
add.signal(qs.strategy,
name="sigFormula",
arguments = list(formula="X1.Buy == 1"),
label="Buy",
cross=FALSE)
add.signal(qs.strategy,
name="sigFormula",
arguments = list(formula="X1.Sell == 1"),
label="Sell",
cross=FALSE)
#
# 7. Rules for buy, sell short, sell and buy to cover
#
nb.contracts <- 2
round.trip.commission.for.one.contract <- 6
round.trip.commission.for.total.contracts <- round.trip.commission.for.one.contract * nb.contracts
add.rule(qs.strategy, 'rulePctEquity',
arguments=list(rebalance_on='months',
trade.percent=1/topchoice,
refprice=quote(last(mktdata[,"price"][paste('::',curIndex,sep='')])),
digits=0
),
type='rebalance',
label='rebalance')
add.rule(qs.strategy,
name='ruleSignal',
arguments = list(sigcol="Sell",
sigval=TRUE,
orderqty='all',
ordertype='market',
orderside='long',
pricemethod='market',
replace=FALSE,TxnFees=-0),
type='exit',
label="LongExit")
add.rule(qs.strategy,
name='ruleSignal',
arguments = list(sigcol="Buy",
sigval=TRUE,
orderqty=1000000000,
ordertype='market',
orderside='long',
replace=FALSE,pricemethod='market',TxnFees=-0,osFUN='osMaxPos'),
type='enter',
label="LongEntry")
posval<-initEq/topchoice
for(symbol in code){
pos<-round((posval/first(get(symbol)[,1])[,1]),0)
addPosLimit(qs.portfolio,symbol,initDate, maxpos=pos,minpos=-pos)
}
#
# 8. Apply Strategy to Porfolio
#
tradeSize <- initEq/topchoice
applyStrategy.rebalancing(strategy = qs.strategy,
portfolios = qs.portfolio)
updatePortf(qs.portfolio, Symbols=code, Dates=paste('::',as.Date(Sys.time()),sep=''))
updateAcct(qs.account)
updateEndEq(qs.account)
[1] "2015-01-02 00:00:00 HK3 3052 @ 10.92020872"
[1] "2015-01-02 00:00:00 HK3 -3052 @ 10.92020872"
[1] "2015-01-02 00:00:00 HK6 1325 @ 25.16659456"
[1] "2015-01-02 00:00:00 HK6 -1325 @ 25.16659456"
[1] "2015-01-02 00:00:00 HK7 1189 @ 28.02736734"
[1] "2015-01-02 00:00:00 HK7 -1189 @ 28.02736734"
[1] "2015-02-01 00:00:00 HK3 33000 @ 11.05592774"
[1] "2015-02-01 00:00:00 HK3 -33000 @ 11.05592774"
[1] "2015-02-01 00:00:00 HK4 33000 @ 16.49518325"
[1] "2015-02-01 00:00:00 HK6 33000 @ 26.05446399"
[1] "2015-02-01 00:00:00 HK6 -33000 @ 26.05446399"
[1] "2015-03-01 00:00:00 HK3 33000 @ 11.90615998"
[1] "2015-03-01 00:00:00 HK3 -33000 @ 11.90615998"
[1] "2015-03-01 00:00:00 HK4 -33000 @ 16.04816942"
[1] "2015-03-01 00:00:00 HK4 33000 @ 16.04816942"
[1] "2015-03-01 00:00:00 HK6 33000 @ 22.68828416"
[1] "2015-03-01 00:00:00 HK6 -33000 @ 22.68828416"
[1] "2015-04-01 00:00:00 HK4 -33000 @ 16.54012275"
[1] "2015-04-01 00:00:00 HK4 -4868 @ 16.54012275"
[1] "2015-04-01 00:00:00 HK4 4868 @ 16.54012275"
[1] "2015-04-01 00:00:00 HK4 23264 @ 16.54012275"
[1] "2015-04-01 00:00:00 HK6 28132 @ 22.04928995"
[1] "2015-04-01 00:00:00 HK6 -28132 @ 22.04928995"
[1] "2015-04-01 00:00:00 HK8 28132 @ 31.03327848"
[1] "2015-05-01 00:00:00 HK4 -23264 @ 14.2995661"
[1] "2015-05-01 00:00:00 HK4 10225 @ 14.2995661"
[1] "2015-05-01 00:00:00 HK4 -10225 @ 14.2995661"
[1] "2015-05-01 00:00:00 HK4 23264 @ 14.2995661"
[1] "2015-05-01 00:00:00 HK6 33489 @ 24.21335116"
[1] "2015-05-01 00:00:00 HK6 -33489 @ 24.21335116"
[1] "2015-05-01 00:00:00 HK8 -28132 @ 32.12345799"
[1] "2015-05-01 00:00:00 HK8 5357 @ 32.12345799"
[1] "2015-05-01 00:00:00 HK8 -5357 @ 32.12345799"
[1] "2015-05-01 00:00:00 HK8 28132 @ 32.12345799"
两个问题:
1) 我怎样才能让投资组合在开始购买之前卖掉所有持股?(投资组合现在正在做相反的事情)
2)我不明白为什么到第二个月或更晚的时候数量会变得如此之大,而第一个月还可以。
(3052*10.92+1325*25.03+1189*28.03=~100000=InitEq