Quantstrat Несколько валют. Возможная ошибка в Blotter::UpdateAcct?
Общая информация:
R-версия: 3.1.0
промокашка: 0.8.19
Описание проблемы:
Я пытаюсь реализовать учетную запись Quantstrat, которая использует несколько portofolios с разными валютами.
Итак, вот мои основные настройки:
- 1 счет в евро
- 1 портфель в долларах США
Поэтому для того, чтобы это работало, я должен установить обменный курс, который я основал на данных, полученных с Yahoo. Затем я должен запустить свою базовую стратегию, и на последнем шаге преобразование будет выполнено автоматически с помощью функции updateAcct.
Теперь вот в чем проблема... Я думаю, что функция updateAcct имеет ошибку.
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)
Все работает, пока код не достигнет последней строки.
В последней строке будет дано сообщение об ошибке: Error in isTRUE(invert) : object 'invert' not found
Возможная ошибка: поэтому я решил проверить функцию updateAcct, попробуйте немного отладить здесь... Я почти уверен, что в коде есть ошибка. Предложение if в строке 63 запрашивает isTRUE(инвертировать), но инвертирование создается только в том случае, если оно действительно истинно (см. Еще строку 46 предложения). Но инвертирование не инициализируется, поэтому, если оно на самом деле ложно, код потерпит неудачу.
Вот блоттер исходного кода (оригинал)
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)
}
Вот как я должен выглядеть (строка фрагмента 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
Я думаю, что в блоттере есть ошибка:updateAcct, которая возникает, когда конвертации валюты не нужно инвертировать обменный курс...
Вопрос: я прав, это ошибка? Или я что-то упустил?
PS:
Обычно я бы сообщал об этом как об ошибке, но А) Я не знаю, как сообщить об ошибке авторам. Б) Я все еще новичок с Quantstrat, Blotter и Co., и я думаю, что кто-то другой должен также проверить это (и авторы тоже тусуются здесь довольно часто)...
1 ответ
Спасибо за воспроизводимый пример. Для дальнейшего использования лучше предоставить различие, чем 20-30 строк кода. Мне потребовалось некоторое время, чтобы заметить, что вы только что добавили одну строку.
> 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)
Исправлено в ревизии 1682. Спасибо за отчет!