Проблемы с откорректированными данными закрытия с http://chart.yahoo.com

У меня есть код построения портфеля R, который использует ежедневные скорректированные данные о ценах закрытия от Yahoo. У меня были проблемы со значениями NA, но код уже некоторое время работает. До этих выходных (например, 28 февраля 2015 г.).

Прямо сейчас источник данных yahoo, кажется, полностью сломан, когда я использую функцию tseries get.hist.quote (). Под «сломанным» я подразумеваю, что он не будет правильно возвращать данные для VTV и ряда других ETF. Я не знаю, не работает ли источник временных рядов Yahoo или что-то в этом роде.

Было сообщение (https://stackoverflow.com/a/3507948/2341077), в котором предлагалось изменить URL-адрес в get.hist.quote () с chart.yahoo.com на ichart.yahoo.com решит проблему. Но для меня это ничего не изменило. Еще я убедился, что у меня установлена ​​последняя версия tseries.

Были ли у кого-нибудь еще проблемы с временными рядами близких цен от Yahoo? Мне было интересно, стоит ли мне изменить свой код, чтобы использовать функцию qualmod getSymbols, которая, по-видимому, может использовать финансы Google в качестве источника данных.

Приведенный ниже код написан для чтения сотен символов ETF и возврата матрицы, содержащей данные временных рядов ETF. Предпринята попытка выровнять данные по дате.

Даже когда казалось, что Yahoo предоставляет данные, все еще отсутствовали значения, для решения которых и предназначена функция fillHoles ().

<pre>

#
# Fill "NA" holes in the time series.
#
fillHoles = function(ts.zoo) {
  v_approx = na.approx(ts.zoo, maxgap=4, na.rm=FALSE)
  v_fill = na.fill(v_approx, fill="extend")
  return( v_fill)
}
<i>
#
# The yahoo market data has problems (at least when it's fetched with get.hist.quote()) when the compression
# argument is used to fetch weekly adjusted close data.
#
# Two time series are shown below, for VXF and MINT. The weekly boundaries appear on different dates.
# 
#              VXF
# 2007-04-04 48.55
# 2007-04-09 48.98
# 2007-04-16 49.52 &lt;==
# 2007-04-23 49.70
# 2007-04-30 50.03
# 2007-05-07 50.04 &lt;==
# 
#            MINT
# 2007-04-04 8.03
# 2007-04-09 8.03
# 2007-04-17 7.88 &lt;==
# 2007-04-23 8.11
# 2007-04-30 8.92
# 2007-05-08 9.14 &lt;==
#   
# If the two time series are merged via a cbind NA values
# end up being inserted where the time series don't line up:'
# 
#              VXF MINT
# 2007-04-04 48.55 8.03
# 2007-04-09 48.98 8.03
# 2007-04-16 49.52   NA
# 2007-04-23 49.70 8.11
# 2007-04-30 50.03 8.92
# 2007-05-07 50.04   NA
#
# To avoid this problem of data alignment, the function fetches daily adjusted close that can then be converted
# into weekly adjusted close.
#
# Given a vector of symbols, this function will fetch the daily adjusted close price data from 
# Yahoo. The data is aligned since not all time series will have exactly the same start and end
# dates (although with daily data, as noted above, this should be less of an issue)
#
</i>
getDailyCloseData = function(symbols, startDate, endDate )
{
  closeData.z = c()
  firstTime = TRUE
  minDate = c()
  maxDate = c()
  fetchedSyms = c()
  startDate.ch = as.character( findMarketDate(as.Date(startDate)))
  endDate.ch = as.character( findMarketDate(as.Date(endDate)))
  for (i in 1:length(symbols)) {
    sym = symbols[i]
    print(sym)
    symClose.z = NULL
    timeOut = 1
    tsEndDate.ch = endDate.ch
    while ((timeOut < 7) && is.null(symClose.z)) {
      try(
        (symClose.z = get.hist.quote(instrument=sym, start=startDate.ch, end=tsEndDate.ch, quote="AdjClose",
                                     provider="yahoo", compression="d", retclass="zoo", quiet=T)),
        silent = TRUE)
      tsEndDate.ch = as.character( findMarketDate( (as.Date(tsEndDate.ch) - 1)))
      timeOut = timeOut + 1
    }
    if (! is.null(symClose.z)) {
      fetchedSyms = c(fetchedSyms, sym)
      dateIx = index(symClose.z)
      if (firstTime) {
        closeData.z = symClose.z
        firstTime = FALSE
        minDate = min(dateIx)
        maxDate = max(dateIx)
      } else {
        minDate = max(minDate, min(dateIx))
        maxDate = min(maxDate, max(dateIx))
        matIx = index(closeData.z)
        repeat {
          startIx = which(matIx == minDate)
          if (length(startIx) > 0 && startIx > 0) {
            break()
          } else {
            minDate = minDate + 1
          }
        } # repeat
        repeat {
           endIx = which(matIx == maxDate)
           if (length(endIx) > 0 && endIx > 0) {
             break()
           } else {
             maxDate = maxDate - 1
           }
        }
        matIxAdj = matIx[startIx:endIx]
        closeData.z = cbind(closeData.z[matIxAdj,], symClose.z[matIxAdj])
      }
    } # if (! is.null(symClose.z))
  } # for
  if (length(closeData.z) > 0) {
    dateIx = index(closeData.z)
     # fill any NA "holes" created by daily date alignment
     closeData.mat = apply(closeData.z, 2, FUN=fillHoles)
     rownames(closeData.mat) = as.character(dateIx)
     colnames(closeData.mat) = fetchedSyms
  }
  return( closeData.mat )
} # getDailyCloseData
</pre>


person iank    schedule 01.03.2015    source источник
comment
Любой воспроизводимый пример?   -  person    schedule 01.03.2015
comment
Одна из проблем заключается в том, что результаты данных Yahoo кажутся спорадическими.   -  person iank    schedule 01.03.2015
comment
Я добавил пример кода для контекста. Однако Yahoo, похоже, не последовательна. Я собираюсь попробовать Google, используя getSymbols () Quantmod.   -  person iank    schedule 01.03.2015


Ответы (2)


Пара замечаний и вопросов. Вы используете get.history.quote для возврата временного ряда зоопарка. Вы пробовали использовать merge.zoo из пакета zoo, чтобы объединить временные истории из разных ресурсов. Это должно без проблем согласовываться по датам. Во-вторых, Google и Yahoo по-разному корректируют исторические цены, поэтому цены на них отличаются. Yahoo предоставляет исторические цены открытия, максимума, минимума и закрытия, а затем скорректированную цену, которая корректируется с учетом дроблений, дивидендов и распределений. Google корректирует все цены, но только для сплитов, игнорируя дивиденды и распределения. Вы можете увидеть эту разницу для данных за 2007 год с помощью VXF.

У меня нет проблем с доступом к Yahoo через getSymbols Quantmod, так что вы можете использовать это вместо перехода на Google. Наконец, согласно Pimco, дата создания MINT - 16.11.2009, поэтому я не понимаю, откуда у вас данные за 2007 год.

Пакет xts - это что-то вроде расширения zoo, которое, как я считаю, имеет некоторые полезные дополнительные функции, такие как to.weekly, который используется ниже. Приведенный ниже код является примером использования пакетов Quantmod и xts для предоставления дневных и недельных цен на ваши ETF. Обратите внимание, что данные MINT не начнутся до 17 ноября 2009 г., что соответствует дате создания Pimco.

library(quantmod)
library(xts)

 getDailyCloseData = function(symbols, startDate, endDate ) {
  close_daily  <- getSymbols(symbols[1], src="yahoo", from=startDate, to=endDate, auto.assign=FALSE)[,6] 
  for(sym in symbols[-1]) {
     close_daily <- merge(close_daily, getSymbols(sym, src="yahoo", from=startDate, to=endDate, auto.assign=FALSE)[,6])
   }
    colnames(close_daily) <- symbols
    return(close_daily)
  }

 symbols <- c("VXF","MINT")
 startDate <- "2007-03-15"
 endDate <- Sys.Date()
 close_daily <- getDailyCloseData(symbols, startDate, endDate)
 close_weekly <- to.weekly(close_daily[,1], OHLC=FALSE)
 for(sym in symbols[-1]) {
   close_weekly <- merge(close_weekly, to.weekly(close_daily[,sym], OHLC=FALSE))
  }
person WaltS    schedule 01.03.2015
comment
Спасибо за сообщение. Я следовал совету, который вы рекомендуете: используйте данные Yahoo через getSymbols (). Как оказалось, использование скорректированных цен закрытия (которые есть только у Yahoo) важно, если вы хотите покупать акции, которые имеют дивиденды. Даже если цена не сильно изменится, скорректированная цена будет двигаться из-за выплаты дивидендов. - person iank; 02.03.2015

Я перешел на использование функции qualmod () getSymbols. Проблемы с данными Yahoo противоречивы, поэтому трудно понять, является ли это полным решением. Но код чище, чем то, что я опубликовал выше.

По правде говоря, если вы инвестируете реальные деньги, а не просто выполняете домашнее задание по количественному финансированию, вам, вероятно, следует покупать данные профессионального уровня.

#
# Find the nearest market date (moving backward in time)
#
findMarketDate = function( date )
{
  while(! isBizday(x = as.timeDate(date), holidays=holidayNYSE(as.numeric(format(date, "%Y"))))) {
    date = date - 1
  }
  return(date)
}

#
# Fill "NA" holes in the time series.
#
fillHoles = function(ts.zoo) {
  v_approx = na.approx(ts.zoo, maxgap=4, na.rm=FALSE)
  v_fill = na.fill(v_approx, fill="extend")
  return( v_fill)
}


#
# Get daily equity market prices (e.g., stocks, ETFs). This code is designed to work
# with both Yahoo and Google. Yahoo is preferred because they have adjusted prices. An adjusted
# price is adjusted for splits and dividends. As a result, an ETF that doesn't move that much in price
# may still move in dividend adjusted price. Using these prices avoids omitting high divident assets.
#
getDailyPriceData = function(symbols, startDate, endDate, dataSource = "yahoo" )
{
  closeData.z = c()
  firstTime = TRUE
  fetchedSyms = c()
  startDate.d = findMarketDate(as.Date(startDate))
  endDate.d = findMarketDate(as.Date(endDate))
  for (i in 1:length(symbols)) {
    sym = symbols[i]
    print(sym)
    close.m = NULL
    timeOut = 1
    while ((timeOut < 7) && is.null(close.m)) {
      try(
        (close.m = getSymbols(Symbols=sym,src=dataSource, auto.assign=getOption('loadSymbols.auto.assign', FALSE),
                              warnings=FALSE)),
        silent = TRUE)
      timeOut = timeOut + 1
    } # while
    if (! is.null(close.m)) {
      dateIx = index(close.m)
      startIx = which(startDate.d == dateIx)
      endIx = which(endDate.d == dateIx)
      if ((length(startIx) > 0 && startIx > 0) && (length(endIx) > 0 && endIx > 0)) {
        fetchedSyms = c(fetchedSyms, sym)
        closeAdj.m = close.m[startIx:endIx,]

        price.z = NULL
        if (dataSource == "yahoo") {
           yahooAdjCol = paste(sym, "Adjusted", sep=".")
           price.z = closeAdj.m[, yahooAdjCol]
        } else {
           highCol = paste(sym, "High", sep=".")
           lowCol = highIx = paste(sym, "Low", sep=".")
           price.z = (closeAdj.m[,highCol] + closeAdj.m[,lowCol])/2
        }
        if (firstTime) {
          closeData.z = price.z
          firstTime = FALSE
        } else {
          closeData.z = cbind(closeData.z, price.z)
        }
      } # if (! is.null(symClose.z))
    } # if not null
  } # for
  closeData.m = c()
  if (length(closeData.z) > 0) {
    dateIx = index(closeData.z)
    closeData.m = coredata(closeData.z)
    numHoles = sum(is.na(closeData.m))
    if (numHoles > 0) {
      # fill any NA "holes" created by daily date alignment
      closeData.m = apply(closeData.m, 2, FUN=fillHoles)
    }
    rownames(closeData.m) = as.character(dateIx)
    colnames(closeData.m) = fetchedSyms
  }
  return( closeData.m )
} # getDailyPriceData

person iank    schedule 02.03.2015