Function 用于创建结果索引的自定义函数

Function 用于创建结果索引的自定义函数,function,r,if-statement,Function,R,If Statement,我试图创建一个函数,创建一个指数(从100开始),然后根据投资结果调整这个指数。因此,简言之,如果第一次投资的利润为5%,那么指数将达到105,如果第二次结果为-7%,那么指数将达到97.65。在这个问题中,当我使用“index”一词时,我不是指zoo包的index功能 除了创建这个索引,我的目标也是创建一个可以应用于我的完整数据集的各种子集的函数(即使用sapply和它的朋友) 以下是我到目前为止拥有的函数(问题末尾的数据): 编辑: 哇,我已经被否决了,虽然我觉得我的问题已经太长了。对不起,

我试图创建一个函数,创建一个指数(从100开始),然后根据投资结果调整这个指数。因此,简言之,如果第一次投资的利润为5%,那么指数将达到105,如果第二次结果为-7%,那么指数将达到97.65。在这个问题中,当我使用“index”一词时,我不是指
zoo
包的
index
功能

除了创建这个索引,我的目标也是创建一个可以应用于我的完整数据集的各种子集的函数(即使用
sapply
和它的朋友)

以下是我到目前为止拥有的函数(问题末尾的数据):

编辑: 哇,我已经被否决了,虽然我觉得我的问题已经太长了。对不起,我认为问题出在我的圈子里,所以我不想让你厌烦细节,因为我认为细节只会给出较少的答案。对不起,我的判断有误

问题是,使用上面的
CalculateIndex
输出,结果与Excel相差很大。即使这可能是由于舍入误差造成的(正如Joris在下面提到的),我对此表示怀疑。与Excel结果相比,R结果差异很大:

R output    Excel calculate values  
99,9790085700   99,97900857 
99,9418035700   99,92081189 
99,6563228600   99,57713687 
101,8868850000  101,4639947 
100,8930864300  102,3570786 
98,9287771400   101,2858564 
102,0291071400  103,3149664 
100,4915864300  103,806556  
98,5295542900   102,3361186 
102,0224285700  104,3585552 
98,4365550000   102,795089  
100,7650171400  103,5601228 
99,3486857100   102,9087897 
100,7640057100  103,6728077 
101,1801400000  104,8529634 
99,7513600000   104,6043164 
97,9013000000   102,5055298 
100,3993485700  102,9048999 
99,8131085700   102,7179995 
101,3496071400  104,0676555 
我认为公平地说,输出的差异不是R与Excel问题的结果,而是我函数中的错误。那么,让我们关注函数

手动计算该函数 该函数使用不同的变量:

  • 大小。单位。
    ;这是在
    EntryPrice
    购买的单位数
  • EntryPrice
    :购买股票的价格
  • TradeResult.Percent.
    :投资产生的收益或损失百分比
  • TradeResult.Currency.
    :投资产生的收益或损失的货币价值($)
这些变量用于函数的以下部分:

100 + ( 100 *((((x$Size.Units. * x$EntryPrice) / totalAccount) * x$TradeResult.Percent.) / 100))

这两个公式本质上是相同的,不同之处在于第一个公式从
100
开始,第二个公式使用
以前的值来计算新的索引值

该公式可分为不同的步骤:

首先,
x$Size.Units.*x$EntryPrice
决定了所采取的总头寸,即以48.98美元的价格购买100股股票的头寸为4898美元

然后将所得的总头寸除以总账户规模(即
总账户
)。这是纠正一个头寸相对于整个投资组合的影响所必需的。例如,如果我们以48.98买入的100股股票下跌10%,那么计算出的指数(即
CalculateIndex
函数)就不必下跌10%,因为
totalAccount
中的资金并非全部投资于一只股票。因此,通过将总头寸除以
总账户
,我们得到一个比率,它告诉我们投资了多少钱。例如,如果股票下跌10%,4898美元(总账户为14000)的头寸将导致账户总损失3.49%。(即
4898/14000=0.349857.0.349857*10%=3.49857%

该比率(投资金额与总金额)在公式中乘以
x$TradeResult.Percent.
,以获得对总账户的百分比影响(见上一段中的计算示例)

最后一步,将总账户的损失百分比应用于指数值(从
100开始)。在这种情况下,100支股票的第一笔投资以48.89美元买入,让我们将指数从100的起点降至99.97901,反映出亏损交易对总账户的影响

编辑结束

将函数剥离干净,然后一次添加一部分公式,以便发现错误,我进入了错误似乎存在的以下步骤:

CalculateIndex <- function(x){
    totalAccount <- accountValueStart
    if(x$TradeResult.Currency == head(x$TradeResult.Currency., n = 1)){
        indexedValues <- totalAccount
        # Update the accountvalue
        totalAccount <- totalAccount + x$TradeResult.Currency.
    }   
    else{ # the value is not the first
        indexedValues <- c(indexedValues, totalAccount)         
            # Update the accountvalue
            totalAccount <- totalAccount + x$TradeResult.Currency.      
    }
    return(indexedValues)
}
> CalculateIndex(theData)
[1] 14000
Warning message:
In if (x$TradeResult.Currency == head(x$TradeResult.Currency., n = 1)) { :
  the condition has length > 1 and only the first element will be used

对于你到底想做什么,我仍然有点困惑,但希望下面的内容会有所帮助

对于第一个值,R脚本给出与Excel函数相同的答案。你会看到不同,因为R并没有打印出所有的数字

> tmp = CalculateIndex(thedata)
Warning message:
In if (x$TradeResult.Currency == head(x$TradeResult.Currency., n = 1)) { :
  the condition has length > 1 and only the first element will be used
> print(tmp, digits=10)
 [1]  99.97900857  99.94180357  99.65632286 101.88688500 100.89308643
 <snip>
>tmp=CalculateIndex(数据)
警告信息:
如果(x$TradeResult.Currency==head(x$TradeResult.Currency.,n=1)){:
条件的长度大于1,并且只使用第一个元素
>打印(tmp,数字=10)
[1]  99.97900857  99.94180357  99.65632286 101.88688500 100.89308643
出现警告消息的原因是因为
x$TradeResult.Currency
是一个与单个数字进行比较的向量


该警告消息也是您的bug所在。在
if
语句中,您从不执行else部分,因为只有
x$TradeResult.Currency
的值被使用。正如警告消息所述,只有
x$TradeResult.Currency
的第一个元素被使用。

警告消息i这句话的意思是:

if(x$TradeResult.Currency == head(x$TradeResult.Currency., n = 1)){
很容易理解为什么;
x$TradeResult.Currency
是一个向量,因此与
head(x$TradeResult.Currency.,n=1)
的比较会产生一个逻辑向量。(顺便问一下,为什么不
x$TradeResult.Currency[1]
而不是
head()
调用?。
if()
需要一个逻辑向量而不是一个逻辑向量,这就是警告的内容。
ifelse()
如果您想根据给出逻辑向量的条件执行以下两项操作之一,则非常有用

实际上,您所做的只是输入stat的
if()
部分
CalculateIndex <- function(x){
    totalAccount <- accountValueStart
    if(x$TradeResult.Currency == head(x$TradeResult.Currency., n = 1)){
        indexedValues <- totalAccount
        # Update the accountvalue
        totalAccount <- totalAccount + x$TradeResult.Currency.
    }   
    else{ # the value is not the first
        indexedValues <- c(indexedValues, totalAccount)         
            # Update the accountvalue
            totalAccount <- totalAccount + x$TradeResult.Currency.      
    }
    return(indexedValues)
}
> CalculateIndex(theData)
[1] 14000
Warning message:
In if (x$TradeResult.Currency == head(x$TradeResult.Currency., n = 1)) { :
  the condition has length > 1 and only the first element will be used
> theData
   Size.Units. EntryPrice TradeResult.Percent. TradeResult.Currency.
1          100      48.98                -0.06                    -3
11         100      32.59                -0.25                    -8
12         100      32.51                -1.48                   -48
2          100      49.01                 5.39                   264
13         100      32.99                 3.79                   125
14         100      34.24                -4.38                  -150
3          100      51.65                 5.50                   284
4          100      48.81                 1.41                    69
15         100      35.74                -5.76                  -206
5          100      49.50                 5.72                   283
6          100      46.67                -4.69                  -219
16         100      33.68                 3.18                   107
7          100      44.48                -2.05                   -91
17         100      32.61                 3.28                   107
8          100      45.39                 3.64                   165
9          100      47.04                -0.74                   -35
10         100      47.39                -6.20                  -294
18         100      33.68                 1.66                    56
19         100      33.12                -0.79                   -26
20         100      32.86                 5.75                   189

theData <- structure(list(X = c(1L, 11L, 12L, 2L, 13L, 14L, 3L, 4L, 15L, 
    5L, 6L, 16L, 7L, 17L, 8L, 9L, 10L, 18L, 19L, 20L), Size.Units. = c(100L, 
    100L, 100L, 100L, 100L, 100L, 100L, 100L, 100L, 100L, 100L, 100L, 
    100L, 100L, 100L, 100L, 100L, 100L, 100L, 100L), EntryPrice = c(48.98, 
    32.59, 32.51, 49.01, 32.99, 34.24, 51.65, 48.81, 35.74, 49.5, 
    46.67, 33.68, 44.48, 32.61, 45.39, 47.04, 47.39, 33.68, 33.12, 
    32.86), TradeResult.Percent. = c(-0.06, -0.25, -1.48, 5.39, 3.79, 
    -4.38, 5.5, 1.41, -5.76, 5.72, -4.69, 3.18, -2.05, 3.28, 3.64, 
    -0.74, -6.2, 1.66, -0.79, 5.75), TradeResult.Currency. = c(-3L, 
    -8L, -48L, 264L, 125L, -150L, 284L, 69L, -206L, 283L, -219L, 
    107L, -91L, 107L, 165L, -35L, -294L, 56L, -26L, 189L)), .Names = c("X", 
    "Size.Units.", "EntryPrice", "TradeResult.Percent.", "TradeResult.Currency."
    ), class = "data.frame", row.names = c(NA, -20L))

# Set the account start @ 14000
> accountValueStart <- 14000
> tmp = CalculateIndex(thedata)
Warning message:
In if (x$TradeResult.Currency == head(x$TradeResult.Currency., n = 1)) { :
  the condition has length > 1 and only the first element will be used
> print(tmp, digits=10)
 [1]  99.97900857  99.94180357  99.65632286 101.88688500 100.89308643
 <snip>
if(x$TradeResult.Currency == head(x$TradeResult.Currency., n = 1)){
> if(c(TRUE, FALSE)) {
+ print("Hi")
+ } else {
+ print("Bye")
+ }
[1] "Hi"
Warning message:
In if (c(TRUE, FALSE)) { :
  the condition has length > 1 and only the first element will be used
> ifelse(c(TRUE, FALSE), print("Hi"), print("Bye"))
[1] "Hi"
[1] "Bye"
[1] "Hi"  "Bye"
CalculateIndex2 <- function(x, value, start = 100) {
    rowSeq <- seq_len(NROW(x))
    totalAc <- cumsum(c(value, x$TradeResult.Currency.))[rowSeq]
    idx <- numeric(length = nrow(x))
    interm <- (((x$Size.Units. * x$EntryPrice) / totalAc) *
               x$TradeResult.Percent.) / 100
    for(i in rowSeq) {
        idx[i] <- start + (start * interm[i])
        start <- idx[i]
    }
    idx
}
> CalculateIndex2(theData, 14000)
 [1]  99.97901  99.92081  99.57714 101.46399 102.35708 101.28586 103.31497
 [8] 103.80656 102.33612 104.35856 102.79509 103.56012 102.90879 103.67281
[15] 104.85296 104.60432 102.50553 102.90490 102.71800 104.06766
CalculateIndex <- function(x,accountValueStart){
  # predifine your vector
  indexedValues <- vector("numeric",nrow(x))
  # get your totalAccount calculated FAST. This is a VECTOR!!!
  totalAccount <- cumsum(c(accountValueStart,x$TradeResult.Currency.))
  #adjust length:
  totalAccount <- totalAccount[-(nrow(x)+1)]

  # only once this calculation. This is a VECTOR!!!!
  totRatio <- 1+(((x$Size.Units. * x$EntryPrice)/totalAccount) *
                 x$TradeResult.Percent.)/100

  # and now the calculations
  indexedValues[1] <- 100 * totRatio[1]
  for(i in 2:nrow(x)){
      indexedValues[i] <- indexedValues[i-1]*totRatio[i]
  }
  return(indexedValues)
}
> CalculateIndex(theData,14000)
[1]  99.97901  99.92081  99.57714 101.46399 102.35708 101.28586 103.31497 
 103.80656 102.33612 104.35856 102.79509 103.56012
[13] 102.90879 103.67281 104.85296 104.60432 102.50553 102.90490 102.71800 
 104.06766
 invisible(replicate(10,print("I will never forget about vectorization any more!")))