【问题标题】:Currency rate calculator to solve the '403 forbidden' from Yahoo解决雅虎“403禁止”的汇率计算器
【发布时间】:2017-11-07 08:14:43
【问题描述】:

和我们许多人一样,当雅虎单方面决定停止提供他们的雅虎财经 API 并收到著名的“403 禁止”消息时,我遇到了一个大问题。 “我们注意到这项服务的使用违反了雅虎服务条款。因此,该服务将被终止。有关所有未来市场和股票数据研究,请参阅finance.yahoo.com。”

就我而言,我所有的主要脚本都是基于他们的货币数据,而我再也无法获得这些数据了。我正在使用“quantmod”包中的“getQuote”函数从雅虎获取数据。

对于所有寻找股票的人,您仍然可以从“quantmod”的“getSymbol.google”函数中获取信息。但对我来说可悲的是,该功能不适用于货币(或者,我无法弄清楚)。

作为捷径,我创建了一个函数来从谷歌金融计算器 (https://finance.google.com/finance/converter?a=1&from=EUR&to=USD&meta=ei%3DEiYAWtCXJ5fBU7HYsig) 中获取数据。

如下所示(我将其称为 CcyCalculator,因为缺少其他想法)我创建了一个函数,您可以指定数量、从哪种货币到您想要的货币汇率。

CcyCalculator <- function(qty=1, convto="USD", QuoteCcy){
url <- paste("http://finance.google.com/finance/converter?a=", qty, "&from=", QuoteCcy, "&to=", convto, "&meta=ei%3DNR4AWtmFOojPUfiBisAE", sep = "") ## look for the web calculator and print it
x <- read.csv(file=url)
x <- x[364,1] ## look for the value
x <-  gsub("^.*?bld>", "", x) ## clean value
x <-  gsub( " .*$", "", x ) ## more cleaning
x <- print(t(as.matrix(c(QuoteCcy, x)))) ## print the value in a matrix 
}

后来,由于我需要许多货币值并且全部以美元兑换率计算,我创建了一个循环来获取向量的所有值。

你需要用你想要获得的货币来指定你的向量。

CcyVector <- c("EUR", "GBP", "JPY", "CHF")

然后你需要创建一个空的数据框来填充数据。

CcyF <- data.frame(x= integer(0), y= numeric(0))

最后,我们用 CcyCalculator 循环我们的 CcyVector

for (i in CcyVector){
Ccy <- paste(CcyCalculator(QuoteCcy = i)) ## loop through CcyVector
CcyF <- as.data.frame(rbind(CcyF, Ccy)) ## ad all the values into our empty data frame
colnames(CcyF) <- c("CCY", "to_USD")
}

而且,如您所见,我们最终得到了一个以美元为单位的货币值的数据框

CCY 转_USD

1.1588 欧元

英镑 1.3152

0.0088 日元

1.0030 瑞士法郎

我不知道这是否会对任何人有所帮助,但我已经尝试了几天,但找不到类似的东西。

如果有人有更好的方法来解决我的问题,或者可以以更清晰、更干净的方式重写我的函数,我将不胜感激(即循环可以用 lapply 替换为 [lapply(CcyVector, CcyCalculator(x) )] 但我无法让它工作)

谢谢!

【问题讨论】:

  • 这是我用来替换 Excel 电子表格 office-watch.com/2016/excel-stock-prices-from-google-finance 中的雅虎股票价格的有用技术。使用不断更新的 Google 表格电子表格的技巧也适用于货币,而且它很容易导入 R 和 Excel。
  • 我意识到 finserv 类型可能总是运行 Excel,但它是一种不必要的依赖,通常充满危险。

标签: r


【解决方案1】:

我怀疑人们可能会关闭您的问题(因为它更像是一篇博客文章而不是 SO)。但是,下面的一些内容可能对偶然发现此问答的其他人有用:

#' Convert currencies using Google Finance calculator
#'
#' @note from, to and qty lengths must meet the following conditions
#'
#' - from, to and qty must all be length 1, *OR*
#' - from, to and qty must all be the _same_ length, *OR*
#' - from can be any length, to can be length 1 and qty can be length 1 or the length of from
#'
#' @param from,to character vectors of currencies to convert from and to.
#' @param qty numeric vector of "from" quantities to convert to "to"
currency_converter <- function(from, to = "USD", qty = 1) {

  # require() only has "real" overhead the first time but we need to
  # ensure these dependencies are loaded and this isn't in a package

  require(httr, quietly=TRUE, warn.conflicts = FALSE)
  require(xml2, quietly=TRUE, warn.conflicts = FALSE)
  require(rvest, quietly=TRUE, warn.conflicts = FALSE)
  require(purrr, quietly=TRUE, warn.conflicts = FALSE)
  require(dplyr, quietly=TRUE, warn.conflicts = FALSE)

  # Local environment variables we'll use liberally in the nested function

  meta <- valid_froms <- valid_tos <- NULL

  # Performs a single conversion

  .currency_converter <- function(.from, .to, .qty) {

    Sys.sleep(5) # just b/c *you* want something for free doesn't give you the right to abuse resources

    if (is.na(.qty)) return(NULL)

    # Prime "meta" & validators with an initial call to the calculator
    # we'll keep updating "meta" in the calculator call until all
    # conversions are done

    if (is.null(meta)) {

      prime <- GET("https://finance.google.com/finance/converter")
      stop_for_status(prime) # shld only happen if you abuse the API or lose network
      prime <- content(prime, as="parsed")

      meta <<- html_attr(html_node(prime, "input[name='meta']"), "value")

      # Get valid from/to & store for later use

      valid_froms <<- html_attr(html_nodes(prime, "select[name='from'] > option"), "value")
      valid_tos <<- html_attr(html_nodes(prime, "select[name='to'] > option"), "value")

    }

    # Make sure the currencies are valid but don't abort if not, just
    # return a data frame with NA for the converted value

    if (!(.from %in% valid_froms)) return(data_frame(from = .from, from_qty = .qty, to = .to, to_qty = NA_real_))
    if (!(.to %in% valid_tos)) return(data_frame(from = .from, from_qty = .qty, to = .to, to_qty = NA_real_))

    # Now make the API call

    httr::GET(
      url = "https://finance.google.com/finance/converter",
      query = list(a = .qty, from = .from, to = .to, meta = meta)
    ) -> res

    stop_for_status(res) # shld only happen if you abuse the API or lose network

    res <- content(res, as="parsed")
    res <- html_text(html_node(res, "div#currency_converter_result > span"))
    res <- as.numeric(sub(" .*$", "", res))

    data_frame(from = .from, from_qty = .qty, to = .to, to_qty = res)

  }

  # Ensure valid params

  if (length(from) > 1) {

    if (length(to) > 1) {
      if (length(to) != length(from)) {
        stop("`from` and `to` must either be the same length or `to` must be a single currency", call.=FALSE)
      }
    } else {
      to <- rep(to, length(from))
    }

    if (length(qty) > 1) {
      if (length(qty) != length(from)) {
        stop("`from`, `to` and `qty` must either be the same length or `qty` must be a single currency", call.=FALSE)
      }
    } else {
      qty <- rep(qty, length(from))
    }

  }

  pmap_dfr(
    data_frame(
      .from = trimws(toupper(from)),
      .to = trimws(toupper(to)),
      .qty = as.numeric(qty)
    ),
    .currency_converter
  )

}

让我们看看它是否有效:

currency_converter("SOS")
## # A tibble: 1 x 4
##    from from_qty    to to_qty
##   <chr>    <dbl> <chr>  <dbl>
## 1   SOS        1   USD 0.0017

currency_converter(c("EUR", "GBP", "JPY", "CHF"))
## # A tibble: 4 x 4
##    from from_qty    to to_qty
##   <chr>    <dbl> <chr>  <dbl>
## 1   EUR        1   USD 1.1570
## 2   GBP        1   USD 1.3138
## 3   JPY        1   USD 0.0087
## 4   CHF        1   USD 0.9992

currency_converter(
  c("EUR", "GBP", "JPY", "CHF"),
  rev(c("EUR", "GBP", "JPY", "CHF"))
)
## # A tibble: 4 x 4
##    from from_qty    to   to_qty
##   <chr>    <dbl> <chr>    <dbl>
## 1   EUR        1   CHF   1.1580
## 2   GBP        1   JPY 150.2182
## 3   JPY        1   GBP   0.0067
## 4   CHF        1   EUR   0.8634

set.seed(8675309)
currency_converter(c("EUR", "GBP", "JPY", "CHF"), "ZAR", sample(20, 4))
## # A tibble: 4 x 4
##    from from_qty    to   to_qty
##   <chr>    <dbl> <chr>    <dbl>
## 1   EUR        4   ZAR  65.6464
## 2   GBP       10   ZAR 186.5290
## 3   JPY       14   ZAR   1.7388
## 4   CHF       18   ZAR 255.2202

currency_converter(
  c("EUR", "GBP", "JPY", "ZZZ"),
  rev(c("EUR", "ZZZ", "JPY", "CHF")),
  sample(20, 4)
)
## # A tibble: 4 x 4
##    from from_qty    to   to_qty
##   <chr>    <dbl> <chr>    <dbl>
## 1   EUR        6   CHF    6.948
## 2   GBP       13   JPY 1952.600
## 3   JPY       18   ZZZ       NA
## 4   ZZZ       15   EUR       NA

【讨论】:

  • 谢谢!这真的很有帮助。我是新来的,我不知道博客类型的问题,下次我会记住的!
猜你喜欢
  • 2016-06-15
  • 2012-12-05
  • 1970-01-01
  • 2016-10-15
  • 1970-01-01
  • 1970-01-01
  • 2020-05-01
  • 1970-01-01
  • 2016-06-19
相关资源
最近更新 更多