1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package com.nickokiss.investor.calc;
22
23 import java.math.BigDecimal;
24 import java.util.List;
25
26 import com.nickokiss.investor.fin.element.CashFlowStream;
27 import com.nickokiss.investor.fin.element.StreamElement;
28 import com.nickokiss.investor.fin.element.StreamElementType;
29 import com.nickokiss.investor.fin.env.Env;
30 import com.nickokiss.investor.function.CashFlowPresentValueFunction;
31 import com.nickokiss.investor.functioncalc.Div2FunctionCalc;
32 import com.nickokiss.investor.util.TkFinConstants;
33 import com.nickokiss.investor.util.TkFinConstructionException;
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50 public class CashFlowStreamCalc {
51
52 private MathCalc mathCalc = new MathCalc();
53
54 public BigDecimal getBenefitsValue(CashFlowStream cashFlowStream, BigDecimal nominalInterestRate, BigDecimal periodsPerYear,
55 BigDecimal timePoint) {
56 List<StreamElement> elements = cashFlowStream.getElements(StreamElementType.BENEFIT);
57 return getValue(elements, nominalInterestRate, periodsPerYear, timePoint);
58 }
59
60 public BigDecimal getCostsValue(CashFlowStream cashFlowStream, BigDecimal nominalInterestRate, BigDecimal periodsPerYear, BigDecimal timePoint) {
61 List<StreamElement> elements = cashFlowStream.getElements(StreamElementType.COST);
62 return getValue(elements, nominalInterestRate, periodsPerYear, timePoint);
63 }
64
65 private BigDecimal getValue(List<StreamElement> elements, BigDecimal nominalInterestRate, BigDecimal periodsPerYear, BigDecimal timePoint) {
66 BigDecimal streamValue = mathCalc.ZERO;
67 for (StreamElement streamElement : elements) {
68 BigDecimal valueAtTime = getStreamElementValue(nominalInterestRate, periodsPerYear, timePoint, streamElement);
69 streamValue = streamValue.add(valueAtTime);
70 }
71 return streamValue;
72 }
73
74 private BigDecimal getStreamElementValue(BigDecimal nominalInterestRate, BigDecimal periodsPerYear, BigDecimal timePoint,
75 StreamElement streamElement) {
76 BigDecimal presentValue = streamElement.getValue();
77 BigDecimal elementTime = streamElement.getTime();
78 BigDecimal timeDifference = timePoint.subtract(elementTime);
79 BigDecimal investmentPeriods = timeDifference.multiply(periodsPerYear);
80 CompoundInterestCalc interestCalc = new CompoundInterestCalc();
81 BigDecimal valueAtTime = interestCalc.getFutureValue(presentValue, nominalInterestRate, periodsPerYear, investmentPeriods);
82 return valueAtTime;
83 }
84
85
86
87
88 public BigDecimal getDuration(CashFlowStream cashFlowStream, BigDecimal nominalInterestRate, BigDecimal periodsPerYear) {
89 BigDecimal timePoint = mathCalc.ZERO;
90 BigDecimal weightedSum = mathCalc.ZERO;
91 List<StreamElement> elements = cashFlowStream.getElements();
92 for (StreamElement streamElement : elements) {
93 BigDecimal valueAtTime = getStreamElementValue(nominalInterestRate, periodsPerYear, timePoint, streamElement);
94 BigDecimal weightedElement = valueAtTime.multiply(streamElement.getTime());
95 weightedSum = weightedSum.add(weightedElement);
96 }
97 BigDecimal presentValue = getPresentValue(cashFlowStream, nominalInterestRate, periodsPerYear);
98 return mathCalc.div(weightedSum, presentValue);
99 }
100
101 public BigDecimal getValue(CashFlowStream cashFlowStream, BigDecimal nominalInterestRate, BigDecimal periodsPerYear, BigDecimal timePoint) {
102 List<StreamElement> elements = cashFlowStream.getElements();
103 return getValue(elements, nominalInterestRate, periodsPerYear, timePoint);
104 }
105
106 public BigDecimal getValueContComp(CashFlowStream cashFlowStream, BigDecimal nominalInterestRate, BigDecimal timePoint) {
107 ContCompInterestCalc interestCalc = new ContCompInterestCalc();
108 List<StreamElement> elements = cashFlowStream.getElements();
109 BigDecimal streamValue = mathCalc.ZERO;
110 for (StreamElement streamElement : elements) {
111 BigDecimal presentValue = streamElement.getValue();
112 BigDecimal elementTime = streamElement.getTime();
113 BigDecimal timeDifference = timePoint.subtract(elementTime);
114 BigDecimal valueAtTime = interestCalc.getFutureValue(presentValue, nominalInterestRate, timeDifference);
115 streamValue = streamValue.add(valueAtTime);
116 }
117 return streamValue;
118
119 }
120
121 public BigDecimal getEndValue(CashFlowStream cashFlowStream, BigDecimal nominalInterestRate, BigDecimal periodsPerYear) {
122 BigDecimal timePoint = cashFlowStream.getEndTime();
123 return getValue(cashFlowStream, nominalInterestRate, periodsPerYear, timePoint);
124 }
125
126 public BigDecimal getStartValue(CashFlowStream cashFlowStream, BigDecimal nominalInterestRate, BigDecimal periodsPerYear) {
127 BigDecimal timePoint = cashFlowStream.getStartTime();
128 return getValue(cashFlowStream, nominalInterestRate, periodsPerYear, timePoint);
129 }
130
131 public BigDecimal getPresentValue(CashFlowStream cashFlowStream, BigDecimal nominalInterestRate, BigDecimal periodsPerYear) {
132 BigDecimal timePoint = mathCalc.ZERO;
133 return getValue(cashFlowStream, nominalInterestRate, periodsPerYear, timePoint);
134 }
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156 public BigDecimal getInfinitePresentValue(CashFlowStream cashFlowCycle, BigDecimal nominalInterestRate, BigDecimal periodsPerYear) {
157 if (cashFlowCycle.length().compareTo(mathCalc.ZERO) == 0) {
158 throw new TkFinConstructionException(TkFinConstants.MESSAGE_INFIN_PV_CYCLE_LENGHT_0);
159 }
160 CompoundInterestCalc intCalc = new CompoundInterestCalc();
161 BigDecimal cyclePV = getStartValue(cashFlowCycle, nominalInterestRate, periodsPerYear);
162 BigDecimal investmentPeriods = cashFlowCycle.length().negate().multiply(periodsPerYear);
163 BigDecimal growth = intCalc.getGrowth(nominalInterestRate, periodsPerYear, investmentPeriods);
164 BigDecimal totalPV = mathCalc.div(cyclePV, mathCalc.ONE.subtract(growth));
165 return totalPV;
166 }
167
168 public BigDecimal getFutureValueContComp(CashFlowStream cashFlowStream, BigDecimal nominalInterestRate) {
169 BigDecimal timePoint = cashFlowStream.getEndTime();
170 return getValueContComp(cashFlowStream, nominalInterestRate, timePoint);
171 }
172
173 public BigDecimal getPresentValueContComp(CashFlowStream cashFlowStream, BigDecimal nominalInterestRate) {
174 BigDecimal timePoint = cashFlowStream.getStartTime();
175 return getValueContComp(cashFlowStream, nominalInterestRate, timePoint);
176 }
177
178
179 public BigDecimal getInternalRateOfReturn(CashFlowStream cashFlowStream, int scale) {
180 BigDecimal expectedFutureValue = mathCalc.ZERO;
181 CashFlowPresentValueFunction function = new CashFlowPresentValueFunction();
182 function.setCashFlowStream(cashFlowStream);
183 Div2FunctionCalc calc = new Div2FunctionCalc();
184 BigDecimal internalRateOfReturn = calc.getParameterForValue(expectedFutureValue, function, scale);
185 return internalRateOfReturn;
186 }
187
188 public BigDecimal getPresentWorthOfBenefits(CashFlowStream cashFlowStream, BigDecimal nominalInterestRate, BigDecimal periodsPerYear) {
189 BigDecimal timePoint = cashFlowStream.getStartTime();
190 return getBenefitsValue(cashFlowStream, nominalInterestRate, periodsPerYear, timePoint);
191 }
192
193 public BigDecimal getPresentWorthOfCosts(CashFlowStream cashFlowStream, BigDecimal nominalInterestRate, BigDecimal periodsPerYear) {
194 BigDecimal timePoint = cashFlowStream.getStartTime();
195 return getCostsValue(cashFlowStream, nominalInterestRate, periodsPerYear, timePoint);
196 }
197
198 public BigDecimal getRunningPresentValue(CashFlowStream cashFlowStream, Env env, BigDecimal time) {
199 int size = cashFlowStream.getElements().size();
200 if (size == 0) {
201 return mathCalc.ZERO;
202 }
203 cashFlowStream.sort();
204 List<StreamElement> streamElements = cashFlowStream.getElements();
205 int lastElementIndex = streamElements.size() - 1;
206 BigDecimal runningPV = streamElements.get(lastElementIndex).getValue();
207 for (int currentIndex = lastElementIndex - 1; currentIndex >= 0; currentIndex--) {
208
209 BigDecimal startTime = streamElements.get(currentIndex).getTime();
210 BigDecimal endTime = streamElements.get(currentIndex + 1).getTime();
211 runningPV = runningPV.multiply(env.getDiscountFactor(startTime, endTime));
212 runningPV = runningPV.add(streamElements.get(currentIndex).getValue());
213 }
214 return runningPV;
215 }
216
217 }