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.fin.element;
22
23 import java.math.BigDecimal;
24 import java.util.ArrayList;
25 import java.util.Collections;
26 import java.util.Comparator;
27 import java.util.List;
28
29 import org.apache.commons.lang.builder.EqualsBuilder;
30 import org.apache.commons.lang.builder.HashCodeBuilder;
31
32 import com.nickokiss.investor.calc.MathCalc;
33 import com.nickokiss.investor.fin.element.creator.StreamElementCreator;
34 import com.nickokiss.investor.fin.env.Env;
35
36
37
38
39
40 public class CashFlowStream implements FinElement {
41
42 private MathCalc mathCalc = new MathCalc();
43
44 private BigDecimal STARTING_TIME = mathCalc.ZERO;
45
46 private List<StreamElement> elements = new ArrayList<StreamElement>();
47
48 public CashFlowStream() {
49 };
50
51 public CashFlowStream(CashFlowStream cashFlowStream) {
52 add(cashFlowStream);
53 }
54
55 public void sort() {
56 Collections.sort(elements, new TimeComparator());
57 }
58
59 public void addElement(StreamElement streamElement) {
60 elements.add(streamElement);
61 }
62
63 public List<StreamElement> getElements() {
64 return elements;
65 }
66
67 public BigDecimal getEndTime() {
68 return Collections.max(elements, new TimeComparator()).getTime();
69 }
70
71 public BigDecimal getStartTime() {
72 return Collections.min(elements, new TimeComparator()).getTime();
73 }
74
75 private class TimeComparator implements Comparator<StreamElement> {
76 public int compare(StreamElement se1, StreamElement se2) {
77 return se1.getTime().compareTo(se2.getTime());
78 }
79 }
80
81 public List<StreamElement> getElements(StreamElementType streamElementType) {
82 List<StreamElement> selectedElements = new ArrayList<StreamElement>();
83 for (StreamElement streamElement : elements) {
84 if (streamElement.getType().equals(streamElementType)) {
85 selectedElements.add(streamElement);
86 }
87 }
88 return selectedElements;
89 }
90
91 public void repeat(int times) {
92 if (times <= 0) {
93 return;
94 }
95 CashFlowStream repeatablePart = new CashFlowStream();
96 repeatablePart.add(this);
97 for (int i = 0; i < times; i++) {
98 add(repeatablePart);
99 }
100 }
101
102 public void add(CashFlowStream cashFlowStream) {
103 CashFlowStream partToAdd = cashFlowStream.getCopy();
104 if (elements.size() > 0) {
105 partToAdd.move(this.length());
106 }
107 elements.addAll(partToAdd.getElements());
108 }
109
110 public int hashCode() {
111 return HashCodeBuilder.reflectionHashCode(this);
112 }
113
114 public boolean equals(Object obj) {
115 return EqualsBuilder.reflectionEquals(this, obj);
116 }
117
118 public BigDecimal length() {
119 return getEndTime().subtract(getStartTime());
120 }
121
122 public void move(BigDecimal time) {
123 for (StreamElement streamElement : elements) {
124 streamElement.setTime(streamElement.getTime().add(time));
125 }
126 }
127
128 public CashFlowStream getCopy() {
129 CashFlowStream copy = new CashFlowStream();
130 for (StreamElement se : elements) {
131 copy.addElement(new StreamElement(se.getValue(), se.getTime()));
132 }
133 return copy;
134 }
135
136 public void addElements(StreamElementCreator streamElementCreator, int quantity) {
137 for (int i = 0; i < quantity; i++) {
138 StreamElement streamElement = streamElementCreator.create(this);
139 addElement(streamElement);
140 }
141
142 }
143
144 public BigDecimal getFirstValue() {
145 return Collections.min(elements, new TimeComparator()).getValue();
146 }
147
148 public BigDecimal getLastValue() {
149 return Collections.max(elements, new TimeComparator()).getValue();
150 }
151
152 private BigDecimal getStartingTime() {
153 if (elements.size() == 0) {
154 return STARTING_TIME;
155 } else {
156 return getEndTime();
157 }
158 }
159
160 public void addElements(BigDecimal value, int quantity, BigDecimal distance) {
161 BigDecimal time = getStartingTime();
162 for (int i = 1; i <= quantity; i++) {
163 time = time.add(distance);
164 addElement(new StreamElement(value, time));
165 }
166 }
167
168 public BigDecimal getValue(Env env, BigDecimal time) {
169 BigDecimal value = mathCalc.ZERO;
170 for (StreamElement finElement : elements) {
171 value = value.add(finElement.getValue(env, time));
172 }
173 return value;
174 }
175
176 public BigDecimal getDuration(Env env) {
177 BigDecimal presentValue = getValue(env, mathCalc.ZERO);
178 BigDecimal weightedSum = mathCalc.ZERO;
179 for (StreamElement element : elements) {
180 BigDecimal timeValue = element.getValue().multiply(element.getTime());
181 BigDecimal durationMultiplicand = env.getDurationMultiplicand(element.getTime());
182 BigDecimal weightedElement = timeValue.multiply(durationMultiplicand);
183 weightedSum = weightedSum.add(weightedElement);
184 }
185 BigDecimal duration = mathCalc.div(weightedSum, presentValue);
186 return duration;
187 }
188
189 }