Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include "analysis.hxx"
21 : #include "analysishelper.hxx"
22 : #include <rtl/math.hxx>
23 :
24 :
25 :
26 0 : double SAL_CALL AnalysisAddIn::getAmordegrc( constREFXPS& xOpt,
27 : double fCost, sal_Int32 nDate, sal_Int32 nFirstPer, double fRestVal,
28 : double fPer, double fRate, const ANY& rOB ) THROWDEF_RTE_IAE
29 : {
30 0 : if( nDate > nFirstPer || fRate <= 0.0 || fRestVal > fCost )
31 0 : THROW_IAE;
32 :
33 0 : double fRet = GetAmordegrc( GetNullDate( xOpt ), fCost, nDate, nFirstPer, fRestVal, fPer, fRate, getDateMode( xOpt, rOB ) );
34 0 : RETURN_FINITE( fRet );
35 : }
36 :
37 :
38 0 : double SAL_CALL AnalysisAddIn::getAmorlinc( constREFXPS& xOpt,
39 : double fCost, sal_Int32 nDate, sal_Int32 nFirstPer, double fRestVal,
40 : double fPer, double fRate, const ANY& rOB ) THROWDEF_RTE_IAE
41 : {
42 0 : if( nDate > nFirstPer || fRate <= 0.0 || fRestVal > fCost )
43 0 : THROW_IAE;
44 :
45 0 : double fRet = GetAmorlinc( GetNullDate( xOpt ), fCost, nDate, nFirstPer, fRestVal, fPer, fRate, getDateMode( xOpt, rOB ) );
46 0 : RETURN_FINITE( fRet );
47 : }
48 :
49 :
50 0 : double SAL_CALL AnalysisAddIn::getAccrint( constREFXPS& xOpt,
51 : sal_Int32 nIssue, sal_Int32 /*nFirstInter*/, sal_Int32 nSettle, double fRate,
52 : const ANY &rVal, sal_Int32 nFreq, const ANY& rOB ) THROWDEF_RTE_IAE
53 : {
54 0 : double fVal = aAnyConv.getDouble( xOpt, rVal, 1000.0 );
55 :
56 0 : if( fRate <= 0.0 || fVal <= 0.0 || CHK_Freq || nIssue >= nSettle )
57 0 : THROW_IAE;
58 :
59 0 : double fRet = fVal * fRate * GetYearDiff( GetNullDate( xOpt ), nIssue, nSettle, getDateMode( xOpt, rOB ) );
60 0 : RETURN_FINITE( fRet );
61 : }
62 :
63 :
64 0 : double SAL_CALL AnalysisAddIn::getAccrintm( constREFXPS& xOpt,
65 : sal_Int32 nIssue, sal_Int32 nSettle, double fRate, const ANY& rVal, const ANY& rOB ) THROWDEF_RTE_IAE
66 : {
67 0 : double fVal = aAnyConv.getDouble( xOpt, rVal, 1000.0 );
68 :
69 0 : if( fRate <= 0.0 || fVal <= 0.0 || nIssue >= nSettle )
70 0 : THROW_IAE;
71 :
72 0 : double fRet = fVal * fRate * GetYearDiff( GetNullDate( xOpt ), nIssue, nSettle, getDateMode( xOpt, rOB ) );
73 0 : RETURN_FINITE( fRet );
74 : }
75 :
76 :
77 0 : double SAL_CALL AnalysisAddIn::getReceived( constREFXPS& xOpt,
78 : sal_Int32 nSettle, sal_Int32 nMat, double fInvest, double fDisc, const ANY& rOB ) THROWDEF_RTE_IAE
79 : {
80 0 : if( fInvest <= 0.0 || fDisc <= 0.0 )
81 0 : THROW_IAE;
82 :
83 0 : double fRet = fInvest / ( 1.0 - ( fDisc * GetYearDiff( GetNullDate( xOpt ), nSettle, nMat, getDateMode( xOpt, rOB ) ) ) );
84 0 : RETURN_FINITE( fRet );
85 : }
86 :
87 :
88 0 : double SAL_CALL AnalysisAddIn::getDisc( constREFXPS& xOpt,
89 : sal_Int32 nSettle, sal_Int32 nMat, double fPrice, double fRedemp, const ANY& rOB ) THROWDEF_RTE_IAE
90 : {
91 0 : if( fPrice <= 0.0 || fRedemp <= 0.0 || nSettle >= nMat )
92 0 : THROW_IAE;
93 0 : double fRet = ( 1.0 - fPrice / fRedemp ) / GetYearFrac( xOpt, nSettle, nMat, getDateMode( xOpt, rOB ) );
94 0 : RETURN_FINITE( fRet );
95 : }
96 :
97 :
98 0 : double SAL_CALL AnalysisAddIn::getDuration( constREFXPS& xOpt,
99 : sal_Int32 nSettle, sal_Int32 nMat, double fCoup, double fYield, sal_Int32 nFreq, const ANY& rOB )
100 : THROWDEF_RTE_IAE
101 : {
102 0 : if( fCoup < 0.0 || fYield < 0.0 || CHK_Freq || nSettle >= nMat )
103 0 : THROW_IAE;
104 :
105 0 : double fRet = GetDuration( GetNullDate( xOpt ), nSettle, nMat, fCoup, fYield, nFreq, getDateMode( xOpt, rOB ) );
106 0 : RETURN_FINITE( fRet );
107 : }
108 :
109 :
110 0 : double SAL_CALL AnalysisAddIn::getEffect( double fNominal, sal_Int32 nPeriods ) THROWDEF_RTE_IAE
111 : {
112 0 : if( nPeriods < 1 || fNominal <= 0.0 )
113 0 : THROW_IAE;
114 :
115 0 : double fPeriods = nPeriods;
116 :
117 0 : double fRet = pow( 1.0 + fNominal / fPeriods, fPeriods ) - 1.0;
118 0 : RETURN_FINITE( fRet );
119 : }
120 :
121 :
122 0 : double SAL_CALL AnalysisAddIn::getCumprinc( double fRate, sal_Int32 nNumPeriods, double fVal,
123 : sal_Int32 nStartPer, sal_Int32 nEndPer, sal_Int32 nPayType ) THROWDEF_RTE_IAE
124 : {
125 : double fRmz, fKapZ;
126 :
127 0 : if( nStartPer < 1 || nEndPer < nStartPer || fRate <= 0.0 || nEndPer > nNumPeriods || nNumPeriods <= 0 ||
128 : fVal <= 0.0 || ( nPayType != 0 && nPayType != 1 ) )
129 0 : THROW_IAE;
130 :
131 0 : fRmz = GetRmz( fRate, nNumPeriods, fVal, 0.0, nPayType );
132 :
133 0 : fKapZ = 0.0;
134 :
135 0 : sal_uInt32 nStart = sal_uInt32( nStartPer );
136 0 : sal_uInt32 nEnd = sal_uInt32( nEndPer );
137 :
138 0 : if( nStart == 1 )
139 : {
140 0 : if( nPayType <= 0 )
141 0 : fKapZ = fRmz + fVal * fRate;
142 : else
143 0 : fKapZ = fRmz;
144 :
145 0 : nStart++;
146 : }
147 :
148 0 : for( sal_uInt32 i = nStart ; i <= nEnd ; i++ )
149 : {
150 0 : if( nPayType > 0 )
151 0 : fKapZ += fRmz - ( GetZw( fRate, double( i - 2 ), fRmz, fVal, 1 ) - fRmz ) * fRate;
152 : else
153 0 : fKapZ += fRmz - GetZw( fRate, double( i - 1 ), fRmz, fVal, 0 ) * fRate;
154 : }
155 :
156 0 : RETURN_FINITE( fKapZ );
157 : }
158 :
159 :
160 0 : double SAL_CALL AnalysisAddIn::getCumipmt( double fRate, sal_Int32 nNumPeriods, double fVal,
161 : sal_Int32 nStartPer, sal_Int32 nEndPer, sal_Int32 nPayType ) THROWDEF_RTE_IAE
162 : {
163 : double fRmz, fZinsZ;
164 :
165 0 : if( nStartPer < 1 || nEndPer < nStartPer || fRate <= 0.0 || nEndPer > nNumPeriods || nNumPeriods <= 0 ||
166 : fVal <= 0.0 || ( nPayType != 0 && nPayType != 1 ) )
167 0 : THROW_IAE;
168 :
169 0 : fRmz = GetRmz( fRate, nNumPeriods, fVal, 0.0, nPayType );
170 :
171 0 : fZinsZ = 0.0;
172 :
173 0 : sal_uInt32 nStart = sal_uInt32( nStartPer );
174 0 : sal_uInt32 nEnd = sal_uInt32( nEndPer );
175 :
176 0 : if( nStart == 1 )
177 : {
178 0 : if( nPayType <= 0 )
179 0 : fZinsZ = -fVal;
180 :
181 0 : nStart++;
182 : }
183 :
184 0 : for( sal_uInt32 i = nStart ; i <= nEnd ; i++ )
185 : {
186 0 : if( nPayType > 0 )
187 0 : fZinsZ += GetZw( fRate, double( i - 2 ), fRmz, fVal, 1 ) - fRmz;
188 : else
189 0 : fZinsZ += GetZw( fRate, double( i - 1 ), fRmz, fVal, 0 );
190 : }
191 :
192 0 : fZinsZ *= fRate;
193 :
194 0 : RETURN_FINITE( fZinsZ );
195 : }
196 :
197 :
198 0 : double SAL_CALL AnalysisAddIn::getPrice( constREFXPS& xOpt,
199 : sal_Int32 nSettle, sal_Int32 nMat, double fRate, double fYield, double fRedemp, sal_Int32 nFreq,
200 : const ANY& rOB ) THROWDEF_RTE_IAE
201 : {
202 0 : if( fYield < 0.0 || fRate < 0.0 || fRedemp <= 0.0 || CHK_Freq || nSettle >= nMat )
203 0 : THROW_IAE;
204 :
205 0 : double fRet = getPrice_( GetNullDate( xOpt ), nSettle, nMat, fRate, fYield, fRedemp, nFreq, getDateMode( xOpt, rOB ) );
206 0 : RETURN_FINITE( fRet );
207 : }
208 :
209 :
210 0 : double SAL_CALL AnalysisAddIn::getPricedisc( constREFXPS& xOpt,
211 : sal_Int32 nSettle, sal_Int32 nMat, double fDisc, double fRedemp, const ANY& rOB ) THROWDEF_RTE_IAE
212 : {
213 0 : if( fDisc <= 0.0 || fRedemp <= 0.0 || nSettle >= nMat )
214 0 : THROW_IAE;
215 :
216 0 : double fRet = fRedemp * ( 1.0 - fDisc * GetYearDiff( GetNullDate( xOpt ), nSettle, nMat, getDateMode( xOpt, rOB ) ) );
217 0 : RETURN_FINITE( fRet );
218 : }
219 :
220 :
221 0 : double SAL_CALL AnalysisAddIn::getPricemat( constREFXPS& xOpt,
222 : sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nIssue, double fRate, double fYield, const ANY& rOB )
223 : THROWDEF_RTE_IAE
224 : {
225 0 : if( fRate < 0.0 || fYield < 0.0 || nSettle >= nMat )
226 0 : THROW_IAE;
227 :
228 0 : sal_Int32 nNullDate = GetNullDate( xOpt );
229 0 : sal_Int32 nBase = getDateMode( xOpt, rOB );
230 :
231 0 : double fIssMat = GetYearFrac( nNullDate, nIssue, nMat, nBase );
232 0 : double fIssSet = GetYearFrac( nNullDate, nIssue, nSettle, nBase );
233 0 : double fSetMat = GetYearFrac( nNullDate, nSettle, nMat, nBase );
234 :
235 0 : double fRet = 1.0 + fIssMat * fRate;
236 0 : fRet /= 1.0 + fSetMat * fYield;
237 0 : fRet -= fIssSet * fRate;
238 0 : fRet *= 100.0;
239 :
240 0 : RETURN_FINITE( fRet );
241 : }
242 :
243 :
244 0 : double SAL_CALL AnalysisAddIn::getMduration( constREFXPS& xOpt,
245 : sal_Int32 nSettle, sal_Int32 nMat, double fCoup, double fYield, sal_Int32 nFreq, const ANY& rOB )
246 : THROWDEF_RTE_IAE
247 : {
248 0 : if( fCoup < 0.0 || fYield < 0.0 || CHK_Freq )
249 0 : THROW_IAE;
250 :
251 0 : double fRet = GetDuration( GetNullDate( xOpt ), nSettle, nMat, fCoup, fYield, nFreq, getDateMode( xOpt, rOB ) );
252 0 : fRet /= 1.0 + ( fYield / double( nFreq ) );
253 0 : RETURN_FINITE( fRet );
254 : }
255 :
256 :
257 0 : double SAL_CALL AnalysisAddIn::getNominal( double fRate, sal_Int32 nPeriods ) THROWDEF_RTE_IAE
258 : {
259 0 : if( fRate <= 0.0 || nPeriods < 0 )
260 0 : THROW_IAE;
261 :
262 0 : double fPeriods = nPeriods;
263 0 : double fRet = ( pow( fRate + 1.0, 1.0 / fPeriods ) - 1.0 ) * fPeriods;
264 0 : RETURN_FINITE( fRet );
265 : }
266 :
267 :
268 0 : double SAL_CALL AnalysisAddIn::getDollarfr( double fDollarDec, sal_Int32 nFrac ) THROWDEF_RTE_IAE
269 : {
270 0 : if( nFrac <= 0 )
271 0 : THROW_IAE;
272 :
273 : double fInt;
274 0 : double fFrac = nFrac;
275 :
276 0 : double fRet = modf( fDollarDec, &fInt );
277 :
278 0 : fRet *= fFrac;
279 :
280 0 : fRet *= pow( 10.0, -ceil( log10( fFrac ) ) );
281 :
282 0 : fRet += fInt;
283 :
284 0 : RETURN_FINITE( fRet );
285 : }
286 :
287 :
288 0 : double SAL_CALL AnalysisAddIn::getDollarde( double fDollarFrac, sal_Int32 nFrac ) THROWDEF_RTE_IAE
289 : {
290 0 : if( nFrac <= 0 )
291 0 : THROW_IAE;
292 :
293 : double fInt;
294 0 : double fFrac = nFrac;
295 :
296 0 : double fRet = modf( fDollarFrac, &fInt );
297 :
298 0 : fRet /= fFrac;
299 :
300 0 : fRet *= pow( 10.0, ceil( log10( fFrac ) ) );
301 :
302 0 : fRet += fInt;
303 :
304 0 : RETURN_FINITE( fRet );
305 : }
306 :
307 :
308 0 : double SAL_CALL AnalysisAddIn::getYield( constREFXPS& xOpt,
309 : sal_Int32 nSettle, sal_Int32 nMat, double fCoup, double fPrice, double fRedemp, sal_Int32 nFreq, const ANY& rOB )
310 : THROWDEF_RTE_IAE
311 : {
312 0 : if( fCoup < 0.0 || fPrice <= 0.0 || fRedemp <= 0.0 || CHK_Freq || nSettle >= nMat )
313 0 : THROW_IAE;
314 :
315 0 : double fRet = getYield_( GetNullDate( xOpt ), nSettle, nMat, fCoup, fPrice, fRedemp, nFreq, getDateMode( xOpt, rOB ) );
316 0 : RETURN_FINITE( fRet );
317 : }
318 :
319 :
320 0 : double SAL_CALL AnalysisAddIn::getYielddisc( constREFXPS& xOpt,
321 : sal_Int32 nSettle, sal_Int32 nMat, double fPrice, double fRedemp, const ANY& rOB ) THROWDEF_RTE_IAE
322 : {
323 0 : if( fPrice <= 0.0 || fRedemp <= 0.0 || nSettle >= nMat )
324 0 : THROW_IAE;
325 :
326 0 : sal_Int32 nNullDate = GetNullDate( xOpt );
327 :
328 0 : double fRet = ( fRedemp / fPrice ) - 1.0;
329 0 : fRet /= GetYearFrac( nNullDate, nSettle, nMat, getDateMode( xOpt, rOB ) );
330 :
331 0 : RETURN_FINITE( fRet );
332 : }
333 :
334 :
335 0 : double SAL_CALL AnalysisAddIn::getYieldmat( constREFXPS& xOpt,
336 : sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nIssue, double fRate, double fPrice, const ANY& rOB )
337 : THROWDEF_RTE_IAE
338 : {
339 0 : if( fPrice <= 0.0 || fRate <= 0.0 || nSettle >= nMat )
340 0 : THROW_IAE;
341 :
342 0 : double fRet = GetYieldmat( GetNullDate( xOpt ), nSettle, nMat, nIssue, fRate, fPrice, getDateMode( xOpt, rOB ) );
343 0 : RETURN_FINITE( fRet );
344 : }
345 :
346 :
347 0 : double SAL_CALL AnalysisAddIn::getTbilleq( constREFXPS& xOpt,
348 : sal_Int32 nSettle, sal_Int32 nMat, double fDisc ) THROWDEF_RTE_IAE
349 : {
350 0 : nMat++;
351 :
352 0 : sal_Int32 nDiff = GetDiffDate360( xOpt, nSettle, nMat, sal_True );
353 :
354 0 : if( fDisc <= 0.0 || nSettle >= nMat || nDiff > 360 )
355 0 : THROW_IAE;
356 :
357 0 : double fRet = ( 365 * fDisc ) / ( 360 - ( fDisc * double( nDiff ) ) );
358 0 : RETURN_FINITE( fRet );
359 : }
360 :
361 :
362 0 : double SAL_CALL AnalysisAddIn::getTbillprice( constREFXPS& xOpt,
363 : sal_Int32 nSettle, sal_Int32 nMat, double fDisc ) THROWDEF_RTE_IAE
364 : {
365 0 : if( fDisc <= 0.0 || nSettle > nMat )
366 0 : THROW_IAE;
367 :
368 0 : nMat++;
369 :
370 0 : double fFraction = GetYearFrac( xOpt, nSettle, nMat, 0 ); // method: USA 30/360
371 :
372 : double fDummy;
373 0 : if( modf( fFraction, &fDummy ) == 0.0 )
374 0 : THROW_IAE;
375 :
376 0 : double fRet = 100.0 * ( 1.0 - fDisc * fFraction );
377 0 : RETURN_FINITE( fRet );
378 : }
379 :
380 :
381 0 : double SAL_CALL AnalysisAddIn::getTbillyield( constREFXPS& xOpt, sal_Int32 nSettle, sal_Int32 nMat, double fPrice )
382 : THROWDEF_RTE_IAE
383 : {
384 0 : sal_Int32 nDiff = GetDiffDate360( xOpt, nSettle, nMat, sal_True );
385 0 : nDiff++;
386 :
387 0 : if( fPrice <= 0.0 || nSettle >= nMat || nDiff > 360 )
388 0 : THROW_IAE;
389 :
390 0 : double fRet = 100.0;
391 0 : fRet /= fPrice;
392 0 : fRet--;
393 0 : fRet /= double( nDiff );
394 0 : fRet *= 360.0;
395 :
396 0 : RETURN_FINITE( fRet );
397 : }
398 :
399 :
400 0 : double SAL_CALL AnalysisAddIn::getOddfprice( constREFXPS& xOpt,
401 : sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nIssue, sal_Int32 nFirstCoup,
402 : double fRate, double fYield, double fRedemp, sal_Int32 nFreq, const ANY& rOB ) THROWDEF_RTE_IAE
403 : {
404 0 : if( fRate < 0.0 || fYield < 0.0 || CHK_Freq || nMat <= nFirstCoup || nFirstCoup <= nSettle || nSettle <= nIssue )
405 0 : THROW_IAE;
406 :
407 0 : double fRet = GetOddfprice( GetNullDate( xOpt ), nSettle, nMat, nIssue, nFirstCoup, fRate, fYield, fRedemp, nFreq, getDateMode( xOpt, rOB ) );
408 0 : RETURN_FINITE( fRet );
409 : }
410 :
411 :
412 0 : double SAL_CALL AnalysisAddIn::getOddfyield( constREFXPS& xOpt,
413 : sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nIssue, sal_Int32 nFirstCoup,
414 : double fRate, double fPrice, double fRedemp, sal_Int32 nFreq, const ANY& rOB ) THROWDEF_RTE_IAE
415 : {
416 0 : if( fRate < 0.0 || fPrice <= 0.0 || CHK_Freq || nMat <= nFirstCoup || nFirstCoup <= nSettle || nSettle <= nIssue )
417 0 : THROW_IAE;
418 :
419 : double fRet = GetOddfyield( GetNullDate( xOpt ), nSettle, nMat, nIssue, nFirstCoup, fRate, fPrice, fRedemp, nFreq,
420 0 : getDateMode( xOpt, rOB ) );
421 0 : RETURN_FINITE( fRet );
422 : }
423 :
424 :
425 0 : double SAL_CALL AnalysisAddIn::getOddlprice( constREFXPS& xOpt,
426 : sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nLastInterest,
427 : double fRate, double fYield, double fRedemp, sal_Int32 nFreq, const ANY& rOB ) THROWDEF_RTE_IAE
428 : {
429 0 : if( fRate < 0.0 || fYield < 0.0 || CHK_Freq || nMat <= nSettle || nSettle <= nLastInterest )
430 0 : THROW_IAE;
431 :
432 : double fRet = GetOddlprice( GetNullDate( xOpt ), nSettle, nMat, nLastInterest, fRate, fYield, fRedemp, nFreq,
433 0 : getDateMode( xOpt, rOB ) );
434 0 : RETURN_FINITE( fRet );
435 : }
436 :
437 :
438 0 : double SAL_CALL AnalysisAddIn::getOddlyield( constREFXPS& xOpt,
439 : sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nLastInterest,
440 : double fRate, double fPrice, double fRedemp, sal_Int32 nFreq, const ANY& rOB ) THROWDEF_RTE_IAE
441 : {
442 0 : if( fRate < 0.0 || fPrice <= 0.0 || CHK_Freq || nMat <= nSettle || nSettle <= nLastInterest )
443 0 : THROW_IAE;
444 :
445 : double fRet = GetOddlyield( GetNullDate( xOpt ), nSettle, nMat, nLastInterest, fRate, fPrice, fRedemp, nFreq,
446 0 : getDateMode( xOpt, rOB ) );
447 0 : RETURN_FINITE( fRet );
448 : }
449 :
450 :
451 : // ============================================================================
452 : // XIRR helper functions
453 :
454 : #define V_(i) (*rValues.Get(i))
455 : #define D_(i) (*rDates.Get(i))
456 :
457 : /** Calculates the resulting amount for the passed interest rate and the given XIRR parameters. */
458 0 : static double lcl_sca_XirrResult( const ScaDoubleList& rValues, const ScaDoubleList& rDates, double fRate )
459 : {
460 : /* V_0 ... V_n = input values.
461 : D_0 ... D_n = input dates.
462 : R = input interest rate.
463 :
464 : r := R+1
465 : E_i := (D_i-D_0) / 365
466 :
467 : n V_i n V_i
468 : f(R) = SUM ------- = V_0 + SUM ------- .
469 : i=0 r^E_i i=1 r^E_i
470 : */
471 0 : double D_0 = D_(0);
472 0 : double r = fRate + 1.0;
473 0 : double fResult = V_(0);
474 0 : for( sal_uInt32 i = 1, nCount = rValues.Count(); i < nCount; ++i )
475 0 : fResult += V_(i) / pow( r, (D_(i) - D_0) / 365.0 );
476 0 : return fResult;
477 : }
478 :
479 : /** Calculates the first derivation of lcl_sca_XirrResult(). */
480 0 : static double lcl_sca_XirrResult_Deriv1( const ScaDoubleList& rValues, const ScaDoubleList& rDates, double fRate )
481 : {
482 : /* V_0 ... V_n = input values.
483 : D_0 ... D_n = input dates.
484 : R = input interest rate.
485 :
486 : r := R+1
487 : E_i := (D_i-D_0) / 365
488 :
489 : n V_i
490 : f'(R) = [ V_0 + SUM ------- ]'
491 : i=1 r^E_i
492 :
493 : n V_i n E_i V_i
494 : = 0 + SUM -E_i ----------- r' = - SUM ----------- .
495 : i=1 r^(E_i+1) i=1 r^(E_i+1)
496 : */
497 0 : double D_0 = D_(0);
498 0 : double r = fRate + 1.0;
499 0 : double fResult = 0.0;
500 0 : for( sal_uInt32 i = 1, nCount = rValues.Count(); i < nCount; ++i )
501 : {
502 0 : double E_i = (D_(i) - D_0) / 365.0;
503 0 : fResult -= E_i * V_(i) / pow( r, E_i + 1.0 );
504 : }
505 0 : return fResult;
506 : }
507 :
508 : #undef V_
509 : #undef D_
510 :
511 :
512 : // ----------------------------------------------------------------------------
513 : // XIRR calculation
514 :
515 0 : double SAL_CALL AnalysisAddIn::getXirr(
516 : constREFXPS& xOpt, const SEQSEQ( double )& rValues, const SEQSEQ( sal_Int32 )& rDates, const ANY& rGuessRate ) THROWDEF_RTE_IAE
517 : {
518 0 : ScaDoubleList aValues, aDates;
519 0 : aValues.Append( rValues );
520 0 : aDates.Append( rDates );
521 :
522 0 : if( (aValues.Count() < 2) || (aValues.Count() != aDates.Count()) )
523 0 : THROW_IAE;
524 :
525 : // result interest rate, initialized with passed guessed rate, or 10%
526 0 : double fResultRate = aAnyConv.getDouble( xOpt, rGuessRate, 0.1 );
527 0 : if( fResultRate <= -1 )
528 0 : THROW_IAE;
529 :
530 : // maximum epsilon for end of iteration
531 : static const double fMaxEps = 1e-10;
532 : // maximum number of iterations
533 : static const sal_Int32 nMaxIter = 50;
534 :
535 : // Newton's method - try to find a fResultRate, so that lcl_sca_XirrResult() returns 0.
536 : double fNewRate, fRateEps, fResultValue;
537 0 : sal_Int32 nIter = 0;
538 : bool bContLoop;
539 0 : do
540 : {
541 0 : fResultValue = lcl_sca_XirrResult( aValues, aDates, fResultRate );
542 0 : fNewRate = fResultRate - fResultValue / lcl_sca_XirrResult_Deriv1( aValues, aDates, fResultRate );
543 0 : fRateEps = fabs( fNewRate - fResultRate );
544 0 : fResultRate = fNewRate;
545 0 : bContLoop = (fRateEps > fMaxEps) && (fabs( fResultValue ) > fMaxEps);
546 : }
547 : while( bContLoop && (++nIter < nMaxIter) );
548 :
549 0 : if( bContLoop )
550 0 : THROW_IAE;
551 0 : RETURN_FINITE( fResultRate );
552 : }
553 :
554 :
555 : // ============================================================================
556 :
557 0 : double SAL_CALL AnalysisAddIn::getXnpv(
558 : double fRate, const SEQSEQ( double )& rValues, const SEQSEQ( sal_Int32 )& rDates ) THROWDEF_RTE_IAE
559 : {
560 0 : ScaDoubleList aValList;
561 0 : ScaDoubleList aDateList;
562 :
563 0 : aValList.Append( rValues );
564 0 : aDateList.Append( rDates );
565 :
566 0 : sal_Int32 nNum = aValList.Count();
567 :
568 0 : if( nNum != sal_Int32( aDateList.Count() ) || nNum < 2 )
569 0 : THROW_IAE;
570 :
571 0 : double fRet = 0.0;
572 0 : double fNull = *aDateList.Get( 0 );
573 0 : fRate++;
574 :
575 0 : for( sal_Int32 i = 0 ; i < nNum ; i++ )
576 0 : fRet += *aValList.Get( i ) / ( pow( fRate, ( *aDateList.Get( i ) - fNull ) / 365.0 ) );
577 :
578 0 : RETURN_FINITE( fRet );
579 : }
580 :
581 :
582 0 : double SAL_CALL AnalysisAddIn::getIntrate( constREFXPS& xOpt,
583 : sal_Int32 nSettle, sal_Int32 nMat, double fInvest, double fRedemp, const ANY& rOB ) THROWDEF_RTE_IAE
584 : {
585 0 : if( fInvest <= 0.0 || fRedemp <= 0.0 || nSettle >= nMat )
586 0 : THROW_IAE;
587 :
588 0 : double fRet = ( ( fRedemp / fInvest ) - 1.0 ) / GetYearDiff( GetNullDate( xOpt ), nSettle, nMat, getDateMode( xOpt, rOB ) );
589 0 : RETURN_FINITE( fRet );
590 : }
591 :
592 :
593 0 : double SAL_CALL AnalysisAddIn::getCoupncd( constREFXPS& xOpt,
594 : sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, const ANY& rOB ) THROWDEF_RTE_IAE
595 : {
596 0 : double fRet = GetCoupncd( GetNullDate( xOpt ), nSettle, nMat, nFreq, getDateMode( xOpt, rOB ) );
597 0 : RETURN_FINITE( fRet );
598 : }
599 :
600 :
601 0 : double SAL_CALL AnalysisAddIn::getCoupdays( constREFXPS& xOpt,
602 : sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, const ANY& rOB ) THROWDEF_RTE_IAE
603 : {
604 0 : double fRet = GetCoupdays( GetNullDate( xOpt ), nSettle, nMat, nFreq, getDateMode( xOpt, rOB ) );
605 0 : RETURN_FINITE( fRet );
606 : }
607 :
608 :
609 0 : double SAL_CALL AnalysisAddIn::getCoupdaysnc( constREFXPS& xOpt,
610 : sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, const ANY& rOB ) THROWDEF_RTE_IAE
611 : {
612 0 : double fRet = GetCoupdaysnc( GetNullDate( xOpt ), nSettle, nMat, nFreq, getDateMode( xOpt, rOB ) );
613 0 : RETURN_FINITE( fRet );
614 : }
615 :
616 :
617 0 : double SAL_CALL AnalysisAddIn::getCoupdaybs( constREFXPS& xOpt,
618 : sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, const ANY& rOB ) THROWDEF_RTE_IAE
619 : {
620 0 : double fRet = GetCoupdaybs( GetNullDate( xOpt ), nSettle, nMat, nFreq, getDateMode( xOpt, rOB ) );
621 0 : RETURN_FINITE( fRet );
622 : }
623 :
624 :
625 0 : double SAL_CALL AnalysisAddIn::getCouppcd( constREFXPS& xOpt,
626 : sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, const ANY& rOB ) THROWDEF_RTE_IAE
627 : {
628 0 : double fRet = GetCouppcd( GetNullDate( xOpt ), nSettle, nMat, nFreq, getDateMode( xOpt, rOB ) );
629 0 : RETURN_FINITE( fRet );
630 : }
631 :
632 :
633 0 : double SAL_CALL AnalysisAddIn::getCoupnum( constREFXPS& xOpt,
634 : sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, const ANY& rOB ) THROWDEF_RTE_IAE
635 : {
636 0 : double fRet = GetCoupnum( GetNullDate( xOpt ), nSettle, nMat, nFreq, getDateMode( xOpt, rOB ) );
637 0 : RETURN_FINITE( fRet );
638 : }
639 :
640 :
641 0 : double SAL_CALL AnalysisAddIn::getFvschedule( double fPrinc, const SEQSEQ( double )& rSchedule ) THROWDEF_RTE_IAE
642 : {
643 0 : ScaDoubleList aSchedList;
644 :
645 0 : aSchedList.Append( rSchedule );
646 :
647 0 : for( const double* p = aSchedList.First() ; p ; p = aSchedList.Next() )
648 0 : fPrinc *= 1.0 + *p;
649 :
650 0 : RETURN_FINITE( fPrinc );
651 : }
652 :
653 :
654 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|