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