Я пытаюсь создать функцию, которая создает индекс (начиная с 100), а затем корректирует этот индекс в соответствии с результатами инвестиций.Итак, в двух словах: если первая инвестиция дает прибыль 5%, то индекс будет равен 105, если второй результат равен -7%, то индекс будет 97,65.В этом вопросе, когда я использую слово «индекс», я не , ссылаясь на функцию index
пакета zoo
.
Помимо создания этого индекса, мой цель - также создать функцию, которая может быть применена к различным подмножествам моего полного набора данных (т. е. с использованием sapply
и его друзей).
Вот функция, которая у меня есть такfar (данные в конце этого вопроса):
CalculateIndex <- function(x){
totalAccount <- accountValueStart
if(x$TradeResult.Currency == head(x$TradeResult.Currency., n = 1)){
indexedValues <- 100 + ( 100 *((((x$Size.Units. * x$EntryPrice) / totalAccount) * x$TradeResult.Percent.) / 100))
# Update the accountvalue
totalAccount <- totalAccount + x$TradeResult.Currency.
}
else{ # the value is not the first
indexedValues <- c(indexedValues,
indexedValues[-1] + (indexedValues[-1] *(((x$Size.Units. * x$EntryPrice) / totalAccount) * x$TradeResult.Percent.) / 100)
)
# Update the accountvalue
totalAccount <- totalAccount + x$TradeResult.Currency.
}
return(indexedValues)
}
В словах функция выполняет (читай: предназначена сделать) следующее: Если значение является первым, используйте 100
какотправная точка для индекса.Если значение не является первым, используйте предыдущее вычисленное значение индекса в качестве отправной точки для расчета нового значения индекса. Кроме того, функция также учитывает вес отдельного результата (по сравнению со значением totalAccount
)
Проблема: Использование этой функции CalculateIndex
во фрейме данных theData
дает следующий неверный вывод:
> CalculateIndex(theData)
[1] 99.97901 99.94180 99.65632 101.88689 100.89309 98.92878 102.02911 100.49159 98.52955 102.02243 98.43655 100.76502 99.34869 100.76401 101.18014 99.75136 97.90130
[18] 100.39935 99.81311 101.34961
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
Редактировать: Ух ты, я уже получил голосование, хотя думал, что мой вопрос уже слишком длинный.Извините, я думал / думаю, что проблема заключалась в моем цикле, поэтому я не хотел утомлять вас деталями, которые, как я думал, дадут меньше ответов.Извините, неправильное суждение с моей стороны.
Проблема заключается в том, что при вышеприведенном выводе CalculateIndex
результаты сильно отличаются от Excel.Даже если это может быть результатом ошибок округления (как упоминает Джорис ниже), я сомневаюсь в этом.По сравнению с результатами 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, но скорееошибка в моей функции.Итак, давайте сосредоточимся на функции.
Ручное вычисление функции Функция использует различные переменные:
Size.Units.
;это количество единиц, которые покупаются по EntryPrice
. EntryPrice
: цене, по которой покупаются акции, TradeResult.Percent.
: процентная прибыль или убыток, полученный в результатеот инвестиции, TradeResult.Currency.
: валютная стоимость ($) прибыли или убытка от инвестиций,
Эти переменные используются в следующем разделе функции:
100 + ( 100 *((((x$Size.Units. * x$EntryPrice) / totalAccount) * x$TradeResult.Percent.) / 100))
и
indexedValues[-1] + (indexedValues[-1] *(((x$Size.Units. * x$EntryPrice) / totalAccount) * x$TradeResult.Percent.) / 100)
Обе формулы по сути одинаковы, с той разницей, что первая начинается с 100
, а вторая использует previous value
рассчитать новое индексированное значение.
Формула может быть разбита на несколько этапов:
Во-первых, x$Size.Units. * x$EntryPrice
определяет общую позицию , которая была занята, в том смысле, что покупка 100 акций поцена 48,98 дает позицию 4898 долл.
Итоговая общая позиция затем делится на общий размер счета (т. е. totalAccount
).Это необходимо для корректировки влияния одной позиции по отношению ко всему портфелю.Например, если наши 100 акций, купленные по 48,98, упали на 10 процентов, вычисленный индекс (то есть функция CalculateIndex
) не должен упасть на 10%, потому что, конечно, не все деньги в totalAccount
инвестируется в одну акцию.Итак, поделив общую позицию на totalAccount
, мы получим коэффициент, который говорит нам, сколько денег вложено.Например, позиция размером 4898 долларов США (на общем счете 14000) приводит к общей потере счета в 3,49%, если акция падает на 10%.(т.е. 4898 / 14000 = 0.349857. 0.349857 * 10% = 3.49857%
)
Это соотношение (суммы инвестирования к общей сумме) затем в формуле умножается на x$TradeResult.Percent.
, чтобы получить процентное влияние на общую сумму (см. Пример расчета в предыдущем абзаце).
В качестве последнего шага процентная потеря на счете total применяется к значению индекса (которое начинается с 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
Итак, похоже, что если я просто использую переменную totalAccount
, функция не будет обновлена правильно. Это говорит о том, что в основах оператора if else
есть некоторая ошибка, поскольку он выводит только первое значение.
Если я удалю оператор else
из функции, я получу значения для каждой строки в theData
. Тем не менее, они тогда неправильно рассчитаны. Итак, мне кажется, что в этой функции обновляется переменная totalAccount
, что-то не так. Я не вижу, где я сделал ошибку, поэтому любые предложения будут высоко оценены. Что я делаю не так?
Данные
Вот как выглядят мои данные:
> 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