首页 文章

Quantstrat多种货币 . Blotter :: UpdateAcct中可能存在错误?

提问于
浏览
3

General info:

R版本:3.1.0

吸墨纸:0.8.19

Problem description:

我正在尝试实现一个使用不同货币的多个portofolios的quantstrat帐户 .

所以这是我的基本设置:

  • 1欧元账户

  • 1美元投资组合

因此,为了实现这一点,我必须设置一个汇率,我根据从雅虎检索到的数据 . 然后我应该运行我的基本策略,转换将在最后一步通过updateAcct函数自动完成 .

现在,这就是问题......我认为updateAcct函数有一个bug .

MyCode:

initDate="1990-01-01"
from="2007-01-01"
to="2012-12-31"
options(width=70)

options("getSymbols.warning4.0"=FALSE) 
currency(c('USD','EUR'))
exchange_rate("USDEUR", tick_size = 0.01)
USDEUR <- Cl(getSymbols("EUR=X",src="yahoo", auto.assign = FALSE))
Sys.setenv(TZ="UTC") 
#not sure why this might work
.blotter <- new.env()
.strategy <- new.env()

symbols <- c("^IXIC" #Nasdaq
             ) 
if(!"XLB" %in% ls()) {
  suppressMessages(getSymbols(symbols, from=from, to=to, src="yahoo", adjust=TRUE))  
  } 

#need this to remove index call symbol (yahoo.) from string. I.e. get ^IXIC, but named IXIC
symbols<-gsub("\\^", "", symbols)

stock(symbols, currency="USD", multiplier=1)

#trade sizing and initial equity settings
tradeSize <- 10000
initEq <- tradeSize*length(symbols) 
strategy.st <- portfolio.st <- account.st <- "TradeNasdaq100"

#clear old strategies etc.
suppressWarnings(try(rm.strat(strategy.st), silent=TRUE))

#initialize portfolio and account
initPortf(portfolio.st, symbols=symbols, initDate=initDate, currency='USD')
initAcct(account.st, portfolios=portfolio.st, initDate=initDate, currency='EUR',initEq=initEq)
initOrders(portfolio.st, initDate=initDate)
strategy(strategy.st, store=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(account.st,dateRange)

一切正常,直到代码到达最后一行 .

The last line will be give the error message: Error in isTRUE(invert) : object 'invert' not found

Possible bug: 所以我决定查看updateAcct函数在这里尝试一点调试......我很确定代码中存在错误 . 第63行中的if子句查询isTRUE(反转),但只有在实际为真的情况下才会创建反转(参见else子句第46行) . 但是反转没有被初始化,因此如果它实际上是假的,代码就会失败 .

Here's the source code blotter (original)

function (name = "default", Dates = NULL) 
{
    Account <- getAccount(name)
    if (!is.null(attr(Account, "currency"))) {
        a.ccy.str <- attr(Account, "currency")
    }
    Portfolios = names(Account$portfolios)
    if (is.null(Dates)) 
        Dates <- unique(do.call(c, c(lapply(Portfolios, function(x) index(.getPortfolio(x)$summary)), 
            use.names = FALSE, recursive = FALSE)))[-1]
    if (!length(Dates)) 
        return(name)
    if (last(index(Account$summary)) > .parseISO8601(Dates)$first.time) {
        whichi <- first(Account$summary[paste(.parseISO8601(Dates)$first.time, 
            "::", sep = ""), which.i = TRUE])
        if (!is.null(whichi)) 
            whichi = whichi - 1
        if (whichi < 1) 
            whichi = 1
        Account$summary = Account$summary[1:whichi, ]
    }
    for (pname in Portfolios) {
        Portfolio = .getPortfolio(pname)
        if (!is.null(attr(Portfolio, "currency"))) {
            p.ccy.str <- attr(Portfolio, "currency")
        }
        psummary = Portfolio$summary[Dates]
        if (a.ccy.str != p.ccy.str) {
            CcyMult <- NA
            port_currency <- try(getInstrument(p.ccy.str), silent = TRUE)
            if (inherits(port_currency, "try-error") | !is.instrument(port_currency)) {
                warning("Currency", p.ccy.str, " not found, using currency multiplier of 1")
                CcyMult <- 1
            }
            else {
                FXrate.str <- paste(p.ccy.str, a.ccy.str, sep = "")
                FXrate <- try(get(FXrate.str), silent = TRUE)
                if (inherits(FXrate, "try-error")) {
                  FXrate.str <- paste(a.ccy.str, p.ccy.str, sep = "")
                  FXrate <- try(get(FXrate.str), silent = TRUE)
                  if (inherits(FXrate, "try-error")) {
                    warning("Exchange Rate", FXrate.str, " not found for symbol,',Symbol,' using currency multiplier of 1")
                    CcyMult <- 1
                  }
                  else {
                    invert = TRUE
                  }
                }
            }
            if (is.na(CcyMult) && !is.na(FXrate)) {
                if (inherits(FXrate, "xts")) {
                  CcyMult <- FXrate[Dates]
                  CcyMult <- na.locf(merge(CcyMult, index(psummary)))
                  CcyMult <- drop(CcyMult[index(psummary)])
                }
                else {
                  CcyMult <- as.numeric(FXrate)
                }
            }
            else {
                CcyMult <- 1
            }
            if (isTRUE(invert)) {
                CcyMult <- 1/CcyMult
            }
            psummary <- psummary * CcyMult
        }
        Account$portfolios[[pname]] = rbind(Account$portfolios[[pname]], 
            psummary)
    }
    summary = NULL
    table = .getByPortf(Account, "Net.Trading.PL", Dates)
    obsLength = length(index(table))
    obsDates = index(table)
    if (obsLength > 1) 
        on = periodicity(table)$units
    else on = "none"
    Attributes = c("Additions", "Withdrawals", "Realized.PL", 
        "Unrealized.PL", "Interest", "Gross.Trading.PL", "Txn.Fees", 
        "Net.Trading.PL", "Advisory.Fees", "Net.Performance", 
        "End.Eq")
    for (Attribute in Attributes) {
        switch(Attribute, Realized.PL = , Unrealized.PL = , Gross.Trading.PL = , 
            Txn.Fees = , Net.Trading.PL = {
                table = .getByPortf(Account, Attribute, Dates)
                result = xts(rowSums(table, na.rm = TRUE), order.by = index(table))
            }, Additions = {
                result = if (on == "none") as.xts(sum(Account$Additions[paste("::", 
                  obsDates, sep = "")]), order.by = index(table)) else {
                  if (length(Account$Additions[obsDates]) > 0) period.apply(Account$Additions[obsDates], 
                    endpoints(Account$Additions[obsDates], on = on), 
                    sum) else xts(rep(0, obsLength), order.by = obsDates)
                }
            }, Withdrawals = {
                result = if (on == "none") as.xts(sum(Account$Withdrawals[paste("::", 
                  obsDates, sep = "")]), order.by = index(table)) else {
                  if (length(Account$Additions[obsDates]) > 0) period.apply(Account$Withdrawals[obsDates], 
                    endpoints(Account$Withdrawals[obsDates], 
                      on = periodicity(table)$units), sum) else xts(rep(0, 
                    obsLength), order.by = obsDates)
                }
            }, Interest = {
                result = if (on == "none") as.xts(sum(Account$Interest[paste("::", 
                  obsDates, sep = "")]), , order.by = index(table)) else {
                  if (length(Account$Additions[obsDates]) > 0) period.apply(Account$Interest[obsDates], 
                    endpoints(Account$Interest[obsDates], on = periodicity(table)$units), 
                    sum) else xts(rep(0, obsLength), order.by = obsDates)
                }
            }, Advisory.Fees = , Net.Performance = , End.Eq = {
                result = xts(rep(0, obsLength), order.by = obsDates)
            })
        colnames(result) = Attribute
        if (is.null(summary)) {
            summary = result
        }
        else {
            summary = cbind(summary, result)
        }
    }
    summary[is.na(summary)] <- 0
    Account$summary <- rbind(Account$summary, summary)
    assign(paste("account", name, sep = "."), Account, envir = .blotter)
    return(name)
}

Here's what I think it should look like (摘录栏28-50)...

if (a.ccy.str != p.ccy.str) {
  CcyMult <- NA
  port_currency <- try(getInstrument(p.ccy.str), silent = TRUE)
  if (inherits(port_currency, "try-error") | !is.instrument(port_currency)) {
    warning("Currency", p.ccy.str, " not found, using currency multiplier of 1")
    CcyMult <- 1
  }
  else {
    FXrate.str <- paste(p.ccy.str, a.ccy.str, sep = "")
    FXrate <- try(get(FXrate.str), silent = TRUE)
    invert=FALSE #THIS IS THE LINE NEEDED FOR FIXING
    if (inherits(FXrate, "try-error")) {
      FXrate.str <- paste(a.ccy.str, p.ccy.str, sep = "")
      FXrate <- try(get(FXrate.str), silent = TRUE)
      if (inherits(FXrate, "try-error")) {
        warning("Exchange Rate", FXrate.str, " not found for symbol,',Symbol,' using currency multiplier of 1")
        CcyMult <- 1
      }
      else {
        invert = TRUE
      }
    }
  }

TL;DR

I think there's bug in blotter:updateAcct which occurs when the currency conversion does not need to invert the exchange rate...

Question: 我是对的,这是一个错误吗?或者我错过了什么?

P.S:

我通常会将此作为一个错误提交但是A)我不知道如何向作者提交错误B)我仍然是一个有量子,吸墨纸和公司的新手,我想其他人也应该检查一下(和作者也经常在这里闲逛......)

1 回答

  • 3

    感谢可重复的例子 . 为了将来参考,最好提供超过20-30行代码的diff . 我花了一段时间注意到你刚刚添加了一行 .

    > svn diff blotter/R/updateAcct.R 
    Index: blotter/R/updateAcct.R
    ===================================================================
    --- blotter/R/updateAcct.R  (revision 1681)
    +++ blotter/R/updateAcct.R  (working copy)
    @@ -51,6 +51,7 @@
                     FXrate.str<-paste(p.ccy.str,a.ccy.str,sep='') # currency quote convention is EURUSD which reads as "USD per EUR"
                     FXrate<-try(get(FXrate.str), silent=TRUE)
                     #TODO FIXME: this uses convention to sort out the rate, we should check $currency and $counter_currency and make sure directionality is correct 
    +                invert=FALSE
                     if(inherits(FXrate,"try-error")){
                         FXrate.str<-paste(a.ccy.str,p.ccy.str,sep='')
                         FXrate<-try(get(FXrate.str), silent=TRUE)
    

    已在revision 1682中修复 . 谢谢你的报道!

相关问题