File indexing completed on 2024-05-12 16:35:31
0001 /* This file is part of the KDE project 0002 Copyright (C) 2007 Sascha Pfau <MrPeacock@gmail.com> 0003 Copyright (C) 2002,2006 Ariya Hidayat <ariya@kde.org> 0004 Copyright (C) 2006 Stefan Nikolaus <stefan.nikolaus@kdemail.net> 0005 Copyright (C) 2005 Tomas Mecir <mecirt@gmail.com> 0006 Copyright (C) 2002 Norbert Andres <nandres@web.de> 0007 Copyright (C) 1999-2000 Laurent Montel <montel@kde.org> 0008 Copyright (C) 1999-2000 Laurent Montel <montel@kde.org> 0009 Copyright (C) 1999-2000 Jonathan Singer <jsinger@genome.wi.mit.edu> 0010 Copyright (C) 1998-1999 Torben Weis <weis@kde.org> 0011 0012 This library is free software; you can redistribute it and/or 0013 modify it under the terms of the GNU Library General Public 0014 License as published by the Free Software Foundation; only 0015 version 2 of the License. 0016 0017 This library is distributed in the hope that it will be useful, 0018 but WITHOUT ANY WARRANTY; without even the implied warranty of 0019 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0020 Library General Public License for more details. 0021 0022 You should have received a copy of the GNU Library General Public License 0023 along with this library; see the file COPYING.LIB. If not, write to 0024 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0025 Boston, MA 02110-1301, USA. 0026 */ 0027 0028 // built-in financial functions 0029 0030 #include "FinancialModule.h" 0031 0032 #include "CalculationSettings.h" 0033 #include "Function.h" 0034 #include "FunctionModuleRegistry.h" 0035 #include "functions/helper.h" 0036 #include "ValueCalc.h" 0037 #include "ValueConverter.h" 0038 0039 #include <kcalendarsystem.h> 0040 0041 #include <math.h> 0042 0043 using namespace Calligra::Sheets; 0044 0045 // prototypes (sorted) 0046 Value func_accrint(valVector args, ValueCalc *calc, FuncExtra *); 0047 Value func_accrintm(valVector args, ValueCalc *calc, FuncExtra *); 0048 Value func_amordegrc(valVector args, ValueCalc *calc, FuncExtra *); 0049 Value func_amorlinc(valVector args, ValueCalc *calc, FuncExtra *); 0050 Value func_compound(valVector args, ValueCalc *calc, FuncExtra *); 0051 Value func_continuous(valVector args, ValueCalc *calc, FuncExtra *); 0052 Value func_coupdaybs (valVector args, ValueCalc *calc, FuncExtra *); 0053 Value func_coupdays (valVector args, ValueCalc *calc, FuncExtra *); 0054 Value func_coupdaysnc (valVector args, ValueCalc *calc, FuncExtra *); 0055 Value func_coupncd (valVector args, ValueCalc *calc, FuncExtra *); 0056 Value func_coupnum(valVector args, ValueCalc *calc, FuncExtra *); 0057 Value func_couppcd (valVector args, ValueCalc *calc, FuncExtra *); 0058 Value func_cumipmt(valVector args, ValueCalc *calc, FuncExtra *); 0059 Value func_cumprinc(valVector args, ValueCalc *calc, FuncExtra *); 0060 Value func_db(valVector args, ValueCalc *calc, FuncExtra *); 0061 Value func_ddb(valVector args, ValueCalc *calc, FuncExtra *); 0062 Value func_disc(valVector args, ValueCalc *calc, FuncExtra *); 0063 Value func_dollarde(valVector args, ValueCalc *calc, FuncExtra *); 0064 Value func_dollarfr(valVector args, ValueCalc *calc, FuncExtra *); 0065 Value func_duration(valVector args, ValueCalc *calc, FuncExtra *); 0066 Value func_duration_add(valVector args, ValueCalc *calc, FuncExtra *); 0067 Value func_effective(valVector args, ValueCalc *calc, FuncExtra *); 0068 Value func_euro(valVector args, ValueCalc *calc, FuncExtra *); 0069 Value func_euroconvert(valVector args, ValueCalc *calc, FuncExtra *); 0070 Value func_fv(valVector args, ValueCalc *calc, FuncExtra *); 0071 Value func_fvschedule(valVector args, ValueCalc *calc, FuncExtra *); 0072 Value func_fv_annuity(valVector args, ValueCalc *calc, FuncExtra *); 0073 Value func_intrate(valVector args, ValueCalc *calc, FuncExtra *); 0074 Value func_ipmt(valVector args, ValueCalc *calc, FuncExtra *); 0075 Value func_irr (valVector args, ValueCalc *calc, FuncExtra *); 0076 Value func_ispmt(valVector args, ValueCalc *calc, FuncExtra *); 0077 Value func_level_coupon(valVector args, ValueCalc *calc, FuncExtra *); 0078 Value func_mduration(valVector args, ValueCalc *calc, FuncExtra *); 0079 Value func_mirr(valVector args, ValueCalc *calc, FuncExtra *); 0080 Value func_nominal(valVector args, ValueCalc *calc, FuncExtra *); 0081 Value func_nper(valVector args, ValueCalc *calc, FuncExtra *); 0082 Value func_npv(valVector args, ValueCalc *calc, FuncExtra *); 0083 // Value func_oddfprice (valVector args, ValueCalc *calc, FuncExtra *); 0084 // Value func_oddfyield (valVector args, ValueCalc *calc, FuncExtra *); 0085 Value func_oddlprice(valVector args, ValueCalc *calc, FuncExtra *); 0086 Value func_oddlyield(valVector args, ValueCalc *calc, FuncExtra *); 0087 Value func_pmt(valVector args, ValueCalc *calc, FuncExtra *); 0088 Value func_ppmt(valVector args, ValueCalc *calc, FuncExtra *); 0089 // Value func_price (valVector args, ValueCalc *calc, FuncExtra *); 0090 // Value func_pricedisc (valVector args, ValueCalc *calc, FuncExtra *); 0091 Value func_pricemat(valVector args, ValueCalc *calc, FuncExtra *); 0092 Value func_pv(valVector args, ValueCalc *calc, FuncExtra *); 0093 Value func_pv_annuity(valVector args, ValueCalc *calc, FuncExtra *); 0094 Value func_rate(valVector args, ValueCalc *calc, FuncExtra *); 0095 Value func_received(valVector args, ValueCalc *calc, FuncExtra *); 0096 Value func_rri(valVector args, ValueCalc *calc, FuncExtra *); 0097 Value func_sln(valVector args, ValueCalc *calc, FuncExtra *); 0098 Value func_syd(valVector args, ValueCalc *calc, FuncExtra *); 0099 Value func_tbilleq(valVector args, ValueCalc *calc, FuncExtra *); 0100 Value func_tbillprice(valVector args, ValueCalc *calc, FuncExtra *); 0101 Value func_tbillyield(valVector args, ValueCalc *calc, FuncExtra *); 0102 Value func_vdb(valVector args, ValueCalc *calc, FuncExtra *); 0103 Value func_xirr(valVector args, ValueCalc *calc, FuncExtra *); 0104 Value func_xnpv(valVector args, ValueCalc *calc, FuncExtra *); 0105 // Value func_yield (valVector args, ValueCalc *calc, FuncExtra *); 0106 Value func_yielddisc(valVector args, ValueCalc *calc, FuncExtra *); 0107 Value func_yieldmat(valVector args, ValueCalc *calc, FuncExtra *); 0108 Value func_zero_coupon(valVector args, ValueCalc *calc, FuncExtra *); 0109 0110 0111 CALLIGRA_SHEETS_EXPORT_FUNCTION_MODULE("kspreadfinancialmodule.json", FinancialModule) 0112 0113 FinancialModule::FinancialModule(QObject* parent, const QVariantList&) 0114 : FunctionModule(parent) 0115 { 0116 Function *f; 0117 0118 f = new Function("ACCRINT", func_accrint); 0119 f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETACCRINT"); 0120 f->setParamCount(6, 7); 0121 add(f); 0122 f = new Function("ACCRINTM", func_accrintm); 0123 f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETACCRINTM"); 0124 f->setParamCount(3, 5); 0125 add(f); 0126 f = new Function("AMORDEGRC", func_amordegrc); 0127 f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETAMORDEGRC"); 0128 f->setParamCount(6, 7); 0129 add(f); 0130 f = new Function("AMORLINC", func_amorlinc); 0131 f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETAMORLINC"); 0132 f->setParamCount(6, 7); 0133 add(f); 0134 f = new Function("COMPOUND", func_compound); 0135 f->setParamCount(4); 0136 add(f); 0137 f = new Function("CONTINUOUS", func_continuous); 0138 f->setParamCount(3); 0139 add(f); 0140 f = new Function ("COUPDAYBS", func_coupdaybs); 0141 f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETCOUPDAYBS"); 0142 f->setParamCount (3, 4); 0143 add(f); 0144 f = new Function ("COUPDAYS", func_coupdays); 0145 f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETCOUPDAYS"); 0146 f->setParamCount (3, 4); 0147 add(f); 0148 f = new Function ("COUPDAYSNC", func_coupdaysnc); 0149 f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETCOUPDAYSNC"); 0150 f->setParamCount (3, 4); 0151 add(f); 0152 f = new Function ("COUPNCD", func_coupncd); 0153 f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETCOUPNCD"); 0154 f->setParamCount (3, 4); 0155 add(f); 0156 f = new Function("COUPNUM", func_coupnum); 0157 f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETCOUPNUM"); 0158 f->setParamCount(3, 5); 0159 add(f); 0160 f = new Function ("COUPPCD", func_couppcd); 0161 f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETCOUPPCD"); 0162 f->setParamCount (3, 4); 0163 add(f); 0164 f = new Function("CUMIPMT", func_cumipmt); 0165 f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETCUMIPMT"); 0166 f->setParamCount(6); 0167 add(f); 0168 f = new Function("CUMPRINC", func_cumprinc); 0169 f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETCUMPRINC"); 0170 f->setParamCount(6); 0171 add(f); 0172 f = new Function("DB", func_db); 0173 f->setParamCount(4, 5); 0174 add(f); 0175 f = new Function("DDB", func_ddb); 0176 f->setParamCount(4, 5); 0177 add(f); 0178 f = new Function("DISC", func_disc); 0179 f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETDISC"); 0180 f->setParamCount(4, 5); 0181 add(f); 0182 f = new Function("DOLLARDE", func_dollarde); 0183 f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETDOLLARDE"); 0184 f->setParamCount(2); 0185 add(f); 0186 f = new Function("DOLLARFR", func_dollarfr); 0187 f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETDOLLARFR"); 0188 f->setParamCount(2); 0189 add(f); 0190 f = new Function("DURATION", func_duration); 0191 f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETDURATION"); 0192 f->setParamCount(3); 0193 add(f); 0194 f = new Function("DURATION_ADD", func_duration_add); 0195 f->setParamCount(5, 6); 0196 add(f); 0197 f = new Function("EFFECT", func_effective); 0198 f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETEFFECT"); 0199 f->setParamCount(2); 0200 add(f); 0201 f = new Function("EFFECTIVE", func_effective); 0202 f->setParamCount(2); 0203 add(f); 0204 f = new Function("EURO", func_euro); // KSpread-specific, Gnumeric-compatible 0205 f->setParamCount(1); 0206 add(f); 0207 f = new Function("EUROCONVERT", func_euroconvert); 0208 f->setParamCount(3); 0209 add(f); 0210 f = new Function("FV", func_fv); 0211 f->setParamCount(3, 5); 0212 add(f); 0213 f = new Function("FVSCHEDULE", func_fvschedule); 0214 f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETFVSCHEDULE"); 0215 f->setParamCount(2); 0216 f->setAcceptArray(); 0217 add(f); 0218 f = new Function("FV_ANNUITY", func_fv_annuity); 0219 f->setParamCount(3); 0220 add(f); 0221 f = new Function("INTRATE", func_intrate); 0222 f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETINTRATE"); 0223 f->setParamCount(4, 5); 0224 add(f); 0225 f = new Function("IPMT", func_ipmt); 0226 f->setParamCount(4, 6); 0227 add(f); 0228 f = new Function ("IRR", func_irr); 0229 f->setParamCount (1, 2); 0230 f->setAcceptArray(); 0231 add(f); 0232 f = new Function("ISPMT", func_ispmt); 0233 f->setParamCount(4); 0234 add(f); 0235 f = new Function("LEVEL_COUPON", func_level_coupon); 0236 f->setParamCount(5); 0237 add(f); 0238 f = new Function("MDURATION", func_mduration); 0239 f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETMDURATION"); 0240 f->setParamCount(5, 6); 0241 add(f); 0242 f = new Function("MIRR", func_mirr); 0243 f->setParamCount(3); 0244 f->setAcceptArray(); 0245 add(f); 0246 f = new Function("NOMINAL", func_nominal); 0247 f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETNOMINAL"); 0248 f->setParamCount(2); 0249 add(f); 0250 f = new Function("NPER", func_nper); 0251 f->setParamCount(3, 5); 0252 add(f); 0253 f = new Function("NPV", func_npv); 0254 f->setParamCount(2, -1); 0255 f->setAcceptArray(); 0256 add(f); 0257 // f = new Function ("ODDFPRICE", func_oddfprice); 0258 // f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETODDFPRICE"); 0259 // f->setParamCount (8, 9); 0260 // add(f); 0261 // f = new Function ("ODDFYIELD", func_oddfyield); 0262 // f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETODDFYIELD"); 0263 // f->setParamCount (8, 9); 0264 // add(f); 0265 f = new Function("ODDLPRICE", func_oddlprice); 0266 f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETODDLPRICE"); 0267 f->setParamCount(7, 8); 0268 add(f); 0269 f = new Function("ODDLYIELD", func_oddlyield); 0270 f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETODDLYIELD"); 0271 f->setParamCount(7, 8); 0272 add(f); 0273 f = new Function("PDURATION", func_duration); 0274 f->setParamCount(3); 0275 add(f); 0276 f = new Function("PMT", func_pmt); 0277 f->setParamCount(3, 5); 0278 add(f); 0279 f = new Function("PPMT", func_ppmt); 0280 f->setParamCount(4, 6); 0281 add(f); 0282 // f = new Function ("PRICE", func_price); 0283 // f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETPRICE"); 0284 // f->setParamCount (6, 7); 0285 // add(f); 0286 // f = new Function ("PRICEDISC", func_pricedisc); 0287 // f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETPRICEDISC"); 0288 // f->setParamCount (4, 5); 0289 // add(f); 0290 f = new Function("PRICEMAT", func_pricemat); 0291 f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETPRICEMAT"); 0292 f->setParamCount(5, 6); 0293 add(f); 0294 f = new Function("PV", func_pv); 0295 f->setParamCount(3, 5); 0296 add(f); 0297 f = new Function("PV_ANNUITY", func_pv_annuity); 0298 f->setParamCount(3); 0299 add(f); 0300 f = new Function ("RATE", func_rate); 0301 f->setParamCount (3, 6); 0302 add(f); 0303 f = new Function("RECEIVED", func_received); 0304 f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETRECEIVED"); 0305 f->setParamCount(4, 5); 0306 add(f); 0307 f = new Function("RRI", func_rri); 0308 f->setParamCount(3); 0309 add(f); 0310 f = new Function("SLN", func_sln); 0311 f->setParamCount(3); 0312 add(f); 0313 f = new Function("SYD", func_syd); 0314 f->setParamCount(4); 0315 add(f); 0316 f = new Function("TBILLEQ", func_tbilleq); 0317 f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETTBILLEQ"); 0318 f->setParamCount(3); 0319 add(f); 0320 f = new Function("TBILLPRICE", func_tbillprice); 0321 f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETTBILLPRICE"); 0322 f->setParamCount(3); 0323 add(f); 0324 f = new Function("TBILLYIELD", func_tbillyield); 0325 f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETTBILLYIELD"); 0326 f->setParamCount(3); 0327 add(f); 0328 f = new Function("VDB", func_vdb); 0329 f->setParamCount(5, 7); 0330 add(f); 0331 f = new Function("XIRR", func_xirr); 0332 f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETXIRR"); 0333 f->setParamCount(2, 3); 0334 f->setAcceptArray(); 0335 add(f); 0336 f = new Function("XNPV", func_xnpv); 0337 f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETXNPV"); 0338 f->setParamCount(3); 0339 f->setAcceptArray(); 0340 add(f); 0341 // f = new Function ("YIELD", func_yield); 0342 // f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETYIELD"); 0343 // f->setParamCount (6, 7); 0344 // add(f); 0345 f = new Function("YIELDDISC", func_yielddisc); 0346 f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETYIELDDISC"); 0347 f->setParamCount(4, 5); 0348 add(f); 0349 f = new Function("YIELDMAT", func_yieldmat); 0350 f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.ANALYSIS.GETYIELDMAT"); 0351 f->setParamCount(5, 6); 0352 add(f); 0353 f = new Function("ZERO_COUPON", func_zero_coupon); 0354 f->setParamCount(3); 0355 add(f); 0356 } 0357 0358 QString FinancialModule::descriptionFileName() const 0359 { 0360 return QString("financial.xml"); 0361 } 0362 0363 0364 /////////////////////////////////////////////////////////////////////////// 0365 0366 // 0367 // helper: awNpv 0368 // 0369 void awNpv(ValueCalc *c, Value &res, Value val, Value rate) 0370 { 0371 Value result = c->conv()->asFloat(res.element(0, 0)); 0372 Value value = c->conv()->asFloat(val); 0373 Value i = c->conv()->asFloat(res.element(1, 0)); 0374 res.setElement(0, 0, c->add(result, c->div(value, c->pow(c->add(Value(1.0), rate), i)))); 0375 res.setElement(1, 0, c->add(i, Value(1.0))); // increment counter 0376 } 0377 0378 // 0379 // helper: calc_fvifa 0380 // 0381 static Value calc_fvifa(ValueCalc * /*calc*/, Value rate, 0382 Value nper) 0383 { 0384 Value res; 0385 0386 if (rate.isZero()) 0387 return (nper); 0388 else 0389 return Value(pow1pm1(rate.asFloat(), nper.asFloat()) / rate.asFloat()); 0390 } 0391 0392 0393 // 0394 // helper: getPay 0395 // 0396 static Value getPay(ValueCalc *calc, Value rate, 0397 Value nper, Value pv, Value fv, Value type) 0398 { 0399 Value pvif, fvifa; 0400 0401 // TODO This is for PMT. Check constraints of the other function using this 0402 //if (calc->isZero (rate)) return Value::errorVALUE(); 0403 if (calc->isZero(rate)) 0404 return calc->mul(calc->div(calc->add(pv, fv), nper), Value(-1.0)); 0405 0406 //pvif = pow( 1 + rate, nper ); 0407 //fvifa = ( pvif - 1 ) / rate; 0408 pvif = Value(pow1p(rate.asFloat(), nper.asFloat())); 0409 // fvifa = calc->div (calc->sub (pvif, 1), rate); 0410 fvifa = calc_fvifa(calc, rate, nper); 0411 0412 // ( -pv * pvif - fv ) / ( ( 1.0 + rate * type ) * fvifa ); 0413 Value val1 = calc->sub(calc->mul(calc->mul(Value(-1), pv), pvif), fv); 0414 Value val2 = calc->mul(calc->add(Value(1.0), calc->mul(rate, type)), 0415 fvifa); 0416 0417 0418 debugSheets << "(1.0 + " << rate << "*" << type << ")*" << fvifa << ") =" << val2; 0419 return calc->div(val1, val2); 0420 } 0421 0422 #if 0 // Not used? 0423 // 0424 // helper: getPrinc 0425 // 0426 static Value getPrinc(ValueCalc *calc, Value start, 0427 Value pay, Value rate, Value period) 0428 { 0429 // val1 = pow( 1 + rate, period ) 0430 Value val1 = calc->pow(calc->add(rate, 1), period); 0431 // val2 = start * val1 0432 Value val2 = calc->mul(start, val1); 0433 // val3 = pay * ( ( val1 - 1 ) / rate ) 0434 Value val3 = calc->mul(pay, calc->div(calc->sub(val1, Value(1)), rate)); 0435 // result = val2 + val3 0436 return calc->add(val2, val3); 0437 } 0438 #endif 0439 // 0440 // helper: eurofactor 0441 // 0442 static double helper_eurofactor(const QString& currency) 0443 { 0444 QString cur = currency.toUpper(); 0445 double result = -1; 0446 0447 if (cur == "ATS") result = 13.7603; // Austria 0448 else if (cur == "BEF") result = 40.3399; // Belgium 0449 else if (cur == "CYP") result = 0.585274; // Cyprus 0450 else if (cur == "DEM") result = 1.95583; // Germany 0451 else if (cur == "EEK") result = 15.6466; // Estonia 0452 else if (cur == "ESP") result = 166.386; // Spain 0453 else if (cur == "EUR") result = 1.0; // Euro 0454 else if (cur == "FIM") result = 5.94573; // Finland 0455 else if (cur == "FRF") result = 6.55957; // France 0456 else if (cur == "GRD") result = 340.75; // Greece 0457 else if (cur == "IEP") result = 0.787564; // Ireland 0458 else if (cur == "ITL") result = 1936.27; // Italy 0459 else if (cur == "LTL") result = 3.45280; // Lithuania 0460 else if (cur == "LUX") result = 40.3399; // Luxembourg <-- This is the wrong code only here for compatibility with old versions 0461 else if (cur == "LUF") result = 40.3399; // Luxembourg 0462 else if (cur == "LVL") result = 0.702804; // Latvia 0463 else if (cur == "MTL") result = 0.4293; // Malta 0464 else if (cur == "NLG") result = 2.20371; // Netherlands 0465 else if (cur == "PTE") result = 200.482; // Portugal 0466 else if (cur == "SIT") result = 239.64; // Slovenia 0467 else if (cur == "SKK") result = 30.126; // Slovakia 0468 0469 return result; 0470 } 0471 0472 // 0473 // helper for IPMT and CUMIPMT is calculation of IPMT 0474 // 0475 static Value helper_ipmt(ValueCalc* calc, Value rate, Value per, Value nper, Value pv, Value fv, Value type) 0476 { 0477 // const Value payment = getPay (calc, rate, nper, pv, fv, type); 0478 // const Value ineg = getPrinc (calc, pv, payment, rate, calc->sub (per, Value(1))); 0479 // // -ineg * rate 0480 // return calc->mul (calc->mul (ineg, Value(-1)), rate); 0481 0482 const Value pmt = getPay(calc, rate, nper, pv, fv, Value(0)); // Type 0 0483 0484 // pow1p (rate, per-1) 0485 const Value val1(pow1p(rate.asFloat(), calc->sub(per, Value(1)).asFloat())); 0486 // pow1pm1 (rate, per-1) 0487 const Value val2(pow1pm1(rate.asFloat(), calc->sub(per, Value(1)).asFloat())); 0488 0489 Value ipmt; 0490 // -1*(pv * pow1p(rate, per-1)*rate + pmt* pow1pm1(rate, per-1)) 0491 ipmt = calc->mul(Value(-1), calc->add(calc->mul(calc->mul(pv, val1), rate), calc->mul(pmt, val2))); 0492 0493 return (type.isZero()) ? ipmt : calc->div(ipmt, calc->add(Value(1), rate)); 0494 } 0495 0496 0497 // 0498 // helper vdbGetGDA 0499 // 0500 static double vdbGetGDA(const double cost, const double salvage, const double life, 0501 const double period, const double depreciationFactor) 0502 { 0503 double res, rate, oldCost, newCost; 0504 0505 rate = depreciationFactor / life; 0506 if (rate >= 1.0) { 0507 rate = 1.0; 0508 if (period == 1.0) 0509 oldCost = cost; 0510 else 0511 oldCost = 0.0; 0512 } else 0513 oldCost = cost * pow(1.0 - rate, period - 1.0); 0514 0515 newCost = cost * pow(1.0 - rate, period); 0516 0517 if (newCost < salvage) 0518 res = oldCost - salvage; 0519 else 0520 res = oldCost - newCost; 0521 0522 if (res < 0.0) 0523 res = 0.0; 0524 0525 return (res); 0526 } 0527 0528 0529 // 0530 // helper vdbInterVDB 0531 // 0532 static double vdbInterVDB(const double cost, const double salvage, 0533 const double life, const double life1, 0534 const double period, const double depreciationFactor) 0535 { 0536 double res = 0.0; 0537 0538 double intEnd = ceil(period); 0539 unsigned long loopEnd = (unsigned long) intEnd; 0540 0541 double term, lia = 0; 0542 double balance = cost - salvage; 0543 bool nowLia = false; 0544 double gda; 0545 unsigned long i; 0546 0547 for (i = 1; i <= loopEnd; ++i) { 0548 if (!nowLia) { 0549 gda = vdbGetGDA(cost, salvage, life, (double) i, depreciationFactor); 0550 lia = balance / (life1 - (double)(i - 1)); 0551 0552 if (lia > gda) { 0553 term = lia; 0554 nowLia = true; 0555 } else { 0556 term = gda; 0557 balance -= gda; 0558 } 0559 } else { 0560 term = lia; 0561 } 0562 0563 if (i == loopEnd) 0564 term *= (period + 1.0 - intEnd); 0565 0566 res += term; 0567 } 0568 0569 return (res); 0570 } 0571 0572 0573 // 0574 // helper: xirrResult 0575 // 0576 // args[0] = values 0577 // args[1] = dates 0578 // 0579 static double xirrResult(valVector& args, ValueCalc *calc, double& rate) 0580 { 0581 QDate date; 0582 0583 QDate date0 = calc->conv()->asDate(args[1].element(0)).asDate(calc->settings()); 0584 0585 double r = rate + 1.0; 0586 double res = calc->conv()->asFloat(args[0].element(0)).asFloat(); 0587 0588 for (int i = 1, count = args[0].count(); i < count; ++i) { 0589 date = calc->conv()->asDate(args[1].element(i)).asDate(calc->settings()); 0590 double e_i = (date0.daysTo(date)) / 365.0; 0591 double val = calc->conv()->asFloat(args[0].element(i)).asFloat(); 0592 0593 res += val / pow(r, e_i); 0594 } 0595 0596 return res; 0597 } 0598 0599 0600 // 0601 // helper: xirrResultDerive 0602 // 0603 // args[0] = values 0604 // args[1] = dates 0605 // 0606 static double xirrResultDerive(valVector& args, ValueCalc *calc, double& rate) 0607 { 0608 QDate date; 0609 0610 QDate date0 = calc->conv()->asDate(args[1].element(0)).asDate(calc->settings()); 0611 0612 double r = rate + 1.0; 0613 double res = 0.0; 0614 0615 for (int i = 1, count = args[0].count(); i < count; ++i) { 0616 date = calc->conv()->asDate(args[1].element(i)).asDate(calc->settings()); 0617 double e_i = (date0.daysTo(date)) / 365.0; 0618 double val = calc->conv()->asFloat(args[0].element(i)).asFloat(); 0619 0620 res -= e_i * val / pow(r, e_i + 1.0); 0621 } 0622 0623 return res; 0624 } 0625 0626 0627 /////////////////////////////////////////////////////////////////////////////////////////////// 0628 0629 0630 // 0631 // Function: ACCRINT 0632 // 0633 Value func_accrint(valVector args, ValueCalc *calc, FuncExtra *) 0634 { 0635 QDate maturity = calc->conv()->asDate(args[0]).asDate(calc->settings()); 0636 QDate settlement = calc->conv()->asDate(args[2]).asDate(calc->settings()); 0637 0638 Value rate = args[3]; 0639 Value par = args[4]; 0640 int frequency = calc->conv()->asInteger(args[5]).asInteger(); 0641 0642 int basis = 0; 0643 if (args.count() == 7) 0644 basis = calc->conv()->asInteger(args[6]).asInteger(); 0645 0646 if (basis < 0 || basis > 4 || (calc->isZero(Value(frequency))) || 0647 (12 % frequency != 0)) 0648 return Value::errorVALUE(); 0649 0650 if (maturity >= settlement) { 0651 debugSheets << "maturity >= settlement"; 0652 return Value::errorVALUE(); 0653 } 0654 0655 double d = daysBetweenDates(maturity, settlement, basis); 0656 double y = daysPerYear(maturity, basis); 0657 0658 if (d < 0 || y <= 0 || calc->lower(par, Value(0)) || calc->lower(rate, Value(0)) || 0659 calc->isZero(rate)) 0660 return Value::errorVALUE(); 0661 0662 Value coeff = calc->div(calc->mul(par, rate), frequency); 0663 double n = d / y; 0664 0665 return calc->mul(coeff, n * frequency); 0666 } 0667 0668 0669 // 0670 // Function: ACCRINTM 0671 // 0672 Value func_accrintm(valVector args, ValueCalc *calc, FuncExtra *) 0673 { 0674 QDate issue = calc->conv()->asDate(args[0]).asDate(calc->settings()); 0675 QDate maturity = calc->conv()->asDate(args[1]).asDate(calc->settings()); 0676 Value rate = args[2]; 0677 0678 Value par = Value(1000); 0679 int basis = 0; 0680 if (args.count() > 3) 0681 par = args[3]; 0682 if (args.count() == 5) 0683 basis = calc->conv()->asInteger(args[4]).asInteger(); 0684 0685 double d = daysBetweenDates(issue, maturity, basis); 0686 double y = daysPerYear(issue, basis); 0687 0688 if (d < 0 || y <= 0 || calc->isZero(par) || calc->isZero(rate) || 0689 calc->lower(par, Value(0)) || calc->lower(rate, Value(0)) || basis < 0 || basis > 4) 0690 return Value::errorVALUE(); 0691 0692 // par*date * d/y 0693 return calc->mul(calc->mul(par, rate), d / y); 0694 } 0695 0696 0697 // 0698 // Function: AMORDEGRC 0699 // 0700 // AMORDEGRC( Cost; purchaseDate; firstPeriodEndDate; salvage; period; basis) 0701 // 0702 Value func_amordegrc(valVector args, ValueCalc *calc, FuncExtra *) 0703 { 0704 double cost = calc->conv()->asFloat(args[0]).asFloat(); 0705 QDate purchaseDate = calc->conv()->asDate(args[1]).asDate(calc->settings()); 0706 QDate firstPeriodEndDate = calc->conv()->asDate(args[2]).asDate(calc->settings()); 0707 double salvage = calc->conv()->asFloat(args[3]).asFloat(); 0708 int period = calc->conv()->asInteger(args[4]).asInteger(); 0709 double rate = calc->conv()->asFloat(args[5]).asFloat(); 0710 0711 int basis = 0; 0712 if (args.count() > 6) 0713 basis = calc->conv()->asInteger(args[6]).asInteger(); 0714 0715 int n; 0716 double amorCoeff, nRate, rest, usePer; 0717 0718 #define ROUND(x,y) (floor ((x) + 0.5)) 0719 0720 usePer = 1.0 / rate; 0721 0722 if (usePer < 3.0) 0723 amorCoeff = 1.0; 0724 else if (usePer < 5.0) 0725 amorCoeff = 1.5; 0726 else if (usePer <= 6.0) 0727 amorCoeff = 2.0; 0728 else 0729 amorCoeff = 2.5; 0730 0731 QDate date0 = calc->settings()->referenceDate(); // referenceDat 0732 0733 rate *= amorCoeff; 0734 nRate = ROUND(yearFrac(date0, purchaseDate, firstPeriodEndDate, basis) * rate * cost, 0); 0735 cost -= nRate; 0736 rest = cost - salvage; 0737 0738 for (n = 0 ; n < period ; ++n) { 0739 nRate = ROUND(rate * cost, 0); 0740 rest -= nRate; 0741 0742 if (rest < 0.0) { 0743 switch (period - n) { 0744 case 0: 0745 case 1: 0746 return Value(ROUND(cost * 0.5, 0)); 0747 default: 0748 return Value(0.0); 0749 } 0750 } 0751 0752 cost -= nRate; 0753 } 0754 0755 return Value(nRate); 0756 #undef ROUND 0757 } 0758 0759 // 0760 // Function: AMORLINC 0761 // 0762 // AMORLINC( Cost; purchaseDate; firstPeriodEndDate; salvage; period; basis) 0763 // 0764 Value func_amorlinc(valVector args, ValueCalc *calc, FuncExtra *) 0765 { 0766 double cost = calc->conv()->asFloat(args[0]).asFloat(); 0767 QDate purchaseDate = calc->conv()->asDate(args[1]).asDate(calc->settings()); 0768 QDate firstPeriodEndDate = calc->conv()->asDate(args[2]).asDate(calc->settings()); 0769 double salvage = calc->conv()->asFloat(args[3]).asFloat(); 0770 int period = calc->conv()->asInteger(args[4]).asInteger(); 0771 double rate = calc->conv()->asFloat(args[5]).asFloat(); 0772 0773 int basis = 0; 0774 if (args.count() > 6) 0775 basis = calc->conv()->asInteger(args[6]).asInteger(); 0776 0777 QDate date0 = calc->settings()->referenceDate(); // referenceDate 0778 0779 double oneRate = cost * rate; 0780 double costDelta = cost - salvage; 0781 double nullRate = yearFrac(date0, purchaseDate, firstPeriodEndDate, basis) * rate * cost; 0782 int numOfFullPeriods = (cost - salvage - nullRate) / oneRate; 0783 0784 double res ; 0785 0786 if (period == 0) 0787 res = nullRate; 0788 else if (period <= numOfFullPeriods) 0789 res = oneRate; 0790 else if (period == numOfFullPeriods + 1) 0791 res = costDelta - oneRate * numOfFullPeriods - nullRate; 0792 else 0793 res = 0.0; 0794 0795 return Value(res); 0796 #undef ROUND 0797 } 0798 0799 // 0800 // Function: compound 0801 // 0802 // Returns value after compounded interest, given principal, rate, periods 0803 // per year and year 0804 // 0805 Value func_compound(valVector args, ValueCalc *calc, FuncExtra *) 0806 { 0807 Value principal = args[0]; 0808 Value interest = args[1]; 0809 Value periods = args[2]; 0810 Value years = args[3]; 0811 0812 // principal * pow(1+ (interest / periods), periods*years); 0813 Value base = calc->add(calc->div(interest, periods), 1); 0814 return calc->mul(principal, calc->pow(base, calc->mul(periods, years))); 0815 } 0816 0817 0818 // 0819 // Function: continuous 0820 // 0821 // Returns value after continuous compounding of interest, given principal, 0822 // rate and years 0823 // 0824 Value func_continuous(valVector args, ValueCalc *calc, FuncExtra *) 0825 { 0826 // If you still don't understand this, let me know! ;-) jsinger@leeta.net 0827 Value principal = args[0]; 0828 Value interest = args[1]; 0829 Value years = args[2]; 0830 0831 // principal * exp(interest * years) 0832 return calc->mul(principal, calc->exp(calc->mul(interest, years))); 0833 } 0834 0835 0836 enum CoupBasis { 0837 BASIS_MSRB_30_360 = 0, 0838 BASIS_ACT_ACT = 1, 0839 BASIS_ACT_360 = 2, 0840 BASIS_ACT_365 = 3, 0841 BASIS_30E_360 = 4, 0842 BASIS_30Ep_360 = 5 0843 }; 0844 0845 struct CoupSettings { 0846 int frequency; // times-per-year 0847 CoupBasis basis; 0848 bool eom; // not sure what this is... 0849 }; 0850 0851 static Value coup_checkparams(valVector args, ValueCalc *calc, QDate& settlement, QDate& maturity, CoupSettings& conf) 0852 { 0853 settlement = calc->conv()->asDate(args[0]).asDate(calc->settings()); 0854 maturity = calc->conv()->asDate(args[1]).asDate(calc->settings()); 0855 conf.frequency = calc->conv()->asInteger(args[2]).asInteger(); 0856 0857 conf.basis = BASIS_MSRB_30_360; 0858 conf.eom = true; 0859 0860 if (args.count() > 3) 0861 conf.basis = static_cast<CoupBasis>(calc->conv()->asInteger(args[3]).asInteger()); 0862 if (args.count() > 4) 0863 conf.eom = calc->conv()->asBoolean(args[4]).asBoolean(); 0864 0865 if (conf.basis < 0 || conf.basis > 5 || (conf.frequency == 0) || (12 % conf.frequency != 0) 0866 || settlement.daysTo(maturity) <= 0) 0867 return Value::errorVALUE(); 0868 0869 return Value(); 0870 } 0871 0872 0873 static QDate coup_cd(const QDate& settlement, const QDate& maturity, int freq, bool eom, bool next) 0874 { 0875 bool is_eom_special = eom && maturity.day() == maturity.daysInMonth(); 0876 0877 int months = 12 / freq; 0878 int periods = maturity.year() - settlement.year(); 0879 if (periods > 0) 0880 periods = (periods - 1) * freq; 0881 0882 QDate result; 0883 do { 0884 ++periods; 0885 result = maturity.addMonths(-periods * months); 0886 if (is_eom_special) { 0887 result.setDate(result.year(), result.month(), result.daysInMonth()); 0888 } 0889 } while (settlement < result); 0890 0891 if (next) { 0892 periods--; 0893 result = maturity.addMonths(-periods * months); 0894 if (is_eom_special) { 0895 result.setDate(result.year(), result.month(), result.daysInMonth()); 0896 } 0897 } 0898 0899 return result; 0900 } 0901 0902 static int daysBetween_30E_360(const QDate& from, const QDate& to) 0903 { 0904 int y1 = from.year(); 0905 int m1 = from.month(); 0906 int d1 = from.day(); 0907 int y2 = to.year(); 0908 int m2 = to.month(); 0909 int d2 = to.day(); 0910 0911 if (d1 == 31) 0912 d1 = 30; 0913 if (d2 == 31) 0914 d2 = 30; 0915 0916 return (y2 - y1) * 360 + (m2 - m1) * 30 + (d2 - d1); 0917 } 0918 0919 static int daysBetween_30Ep_360(const QDate& from, const QDate& to) 0920 { 0921 int y1 = from.year(); 0922 int m1 = from.month(); 0923 int d1 = from.day(); 0924 int y2 = to.year(); 0925 int m2 = to.month(); 0926 int d2 = to.day(); 0927 0928 if (d1 == 31) 0929 d1 = 30; 0930 if (d2 == 31) { 0931 d2 = 1; 0932 ++m2; 0933 /* No need to check for m2 == 13 since 12*30 == 360 */ 0934 } 0935 0936 return (y2 - y1) * 360 + (m2 - m1) * 30 + (d2 - d1); 0937 } 0938 0939 static int daysBetween_MSRB_30_360(const QDate& from, const QDate& to) 0940 { 0941 int y1 = from.year(); 0942 int m1 = from.month(); 0943 int d1 = from.day(); 0944 int y2 = to.year(); 0945 int m2 = to.month(); 0946 int d2 = to.day(); 0947 0948 if (m1 == 2 && d1 == from.daysInMonth()) 0949 d1 = 30; 0950 if (m2 == 2 && d2 == to.daysInMonth()) 0951 d2 = 30; 0952 if (d2 == 31 && d1 >= 30) 0953 d2 = 30; 0954 if (d1 == 31) 0955 d1 = 30; 0956 0957 return (y2 - y1) * 360 + (m2 - m1) * 30 + (d2 - d1); 0958 } 0959 0960 static int daysBetweenBasis(const QDate& from, const QDate& to, CoupBasis basis) 0961 { 0962 const int sign = from < to ? 1 : -1; 0963 const QDate f = qMin(from, to); 0964 const QDate t = qMax(from, to); 0965 0966 switch (basis) { 0967 case BASIS_ACT_ACT: 0968 case BASIS_ACT_360: 0969 case BASIS_ACT_365: 0970 return sign * f.daysTo(t); 0971 case BASIS_30E_360: 0972 return sign * daysBetween_30E_360(f, t); 0973 case BASIS_30Ep_360: 0974 return sign * daysBetween_30Ep_360(f, t); 0975 case BASIS_MSRB_30_360: 0976 default: 0977 return sign * daysBetween_MSRB_30_360(f, t); 0978 } 0979 } 0980 0981 0982 // 0983 // Function: COUPDAYBS 0984 // 0985 Value func_coupdaybs(valVector args, ValueCalc *calc, FuncExtra *) 0986 { 0987 QDate settlement, maturity; 0988 CoupSettings conf; 0989 0990 Value res = coup_checkparams(args, calc, settlement, maturity, conf); 0991 if (res.isError()) { 0992 return res; 0993 } 0994 0995 QDate d = coup_cd(settlement, maturity, conf.frequency, conf.eom, false); 0996 0997 return Value(daysBetweenBasis(d, settlement, conf.basis)); 0998 } 0999 1000 1001 static double coupdays(const QDate& settlement, const QDate& maturity, const CoupSettings& conf) 1002 { 1003 switch (conf.basis) { 1004 case BASIS_MSRB_30_360: 1005 case BASIS_ACT_360: 1006 case BASIS_30E_360: 1007 case BASIS_30Ep_360: 1008 return 360.0 / conf.frequency; 1009 case BASIS_ACT_365: 1010 return 365.0 / conf.frequency; 1011 case BASIS_ACT_ACT: 1012 default: 1013 QDate next = coup_cd(settlement, maturity, conf.frequency, conf.eom, true); 1014 QDate prev = coup_cd(settlement, maturity, conf.frequency, conf.eom, false); 1015 return daysBetweenBasis(prev, next, BASIS_ACT_ACT); 1016 } 1017 } 1018 1019 // 1020 // Function: COUPDAYS 1021 // 1022 Value func_coupdays(valVector args, ValueCalc *calc, FuncExtra *) 1023 { 1024 QDate settlement, maturity; 1025 CoupSettings conf; 1026 1027 Value res = coup_checkparams(args, calc, settlement, maturity, conf); 1028 if (res.isError()) { 1029 return res; 1030 } 1031 1032 1033 return Value(coupdays(settlement, maturity, conf)); 1034 } 1035 1036 1037 // 1038 // Function: COUPDAYSNC 1039 // 1040 Value func_coupdaysnc(valVector args, ValueCalc *calc, FuncExtra *) 1041 { 1042 QDate settlement, maturity; 1043 CoupSettings conf; 1044 1045 Value res = coup_checkparams(args, calc, settlement, maturity, conf); 1046 if (res.isError()) { 1047 return res; 1048 } 1049 1050 QDate d = coup_cd(settlement, maturity, conf.frequency, conf.eom, true); 1051 1052 return Value(daysBetweenBasis(settlement, d, conf.basis)); 1053 } 1054 1055 1056 // 1057 // Function: COUPNCD 1058 // 1059 Value func_coupncd(valVector args, ValueCalc *calc, FuncExtra *) 1060 { 1061 QDate settlement, maturity; 1062 CoupSettings conf; 1063 1064 Value res = coup_checkparams(args, calc, settlement, maturity, conf); 1065 if (res.isError()) { 1066 return res; 1067 } 1068 1069 return Value(coup_cd(settlement, maturity, conf.frequency, conf.eom, true), calc->settings()); 1070 } 1071 1072 1073 // 1074 // Function: COUPNUM - taken from GNUMERIC 1075 // 1076 // 1077 // COUPNUM ( settlement, maturity, freq, [ basis = 0 ], [ eom ] ) 1078 // 1079 Value func_coupnum(valVector args, ValueCalc *calc, FuncExtra *) 1080 { 1081 // dates and integers only - don't need high-precision for this 1082 QDate settlement = calc->conv()->asDate(args[0]).asDate(calc->settings()); 1083 QDate maturity = calc->conv()->asDate(args[1]).asDate(calc->settings()); 1084 int frequency = calc->conv()->asInteger(args[2]).asInteger(); 1085 1086 // defaults 1087 int basis = 0; 1088 bool eom = true; 1089 1090 if (args.count() > 3) 1091 basis = calc->conv()->asInteger(args[3]).asInteger(); 1092 if (args.count() == 5) 1093 eom = calc->conv()->asBoolean(args[4]).asBoolean(); 1094 1095 if (basis < 0 || basis > 5 || (frequency == 0) || (12 % frequency != 0) 1096 || settlement.daysTo(maturity) <= 0) 1097 return Value::errorVALUE(); 1098 1099 double result; 1100 QDate cDate(maturity); 1101 1102 int months = maturity.month() - settlement.month() 1103 + 12 * (maturity.year() - settlement.year()); 1104 1105 cDate = calc->settings()->locale()->calendar()->addMonths(cDate, -months); 1106 1107 if (eom && maturity.daysInMonth() == maturity.day()) { 1108 while (cDate.daysInMonth() != cDate.day()) 1109 cDate = cDate.addDays(1); 1110 } 1111 1112 if (settlement.day() >= cDate.day()) 1113 --months; 1114 1115 result = (1 + months / (12 / frequency)); 1116 1117 return Value(result); 1118 } 1119 1120 1121 // 1122 // Function: COUPPCD 1123 // 1124 Value func_couppcd(valVector args, ValueCalc *calc, FuncExtra *) 1125 { 1126 QDate settlement, maturity; 1127 CoupSettings conf; 1128 1129 Value res = coup_checkparams(args, calc, settlement, maturity, conf); 1130 if (res.isError()) { 1131 return res; 1132 } 1133 1134 return Value(coup_cd(settlement, maturity, conf.frequency, conf.eom, false), calc->settings()); 1135 } 1136 1137 1138 // 1139 // Function: CUMIPMT 1140 // 1141 Value func_cumipmt(valVector args, ValueCalc *calc, FuncExtra *) 1142 { 1143 const Value rate = args[0]; 1144 if (rate.asFloat() <= 0.0) 1145 return Value::errorVALUE(); 1146 const Value nper = args[1]; 1147 const int periods = nper.asInteger(); 1148 if (periods <= 0) 1149 return Value::errorVALUE(); 1150 const Value pv = args[2]; 1151 if (pv.asFloat() <= 0.0) 1152 return Value::errorVALUE(); 1153 const Value v1(calc->conv()->asInteger(args[3])); 1154 if (v1.isError()) 1155 return Value::errorVALUE(); 1156 const int start = v1.asInteger(); 1157 if (start <= 0 || start > periods) 1158 return Value::errorVALUE(); 1159 const Value v2(calc->conv()->asInteger(args[4])); 1160 if (v2.isError()) 1161 return Value::errorVALUE(); 1162 const int end = v2.asInteger(); 1163 if (end < start || end > periods) 1164 return Value::errorVALUE(); 1165 const Value type(calc->conv()->asInteger(args[5])); 1166 if (type.isError()) 1167 return Value::errorVALUE(); 1168 1169 Value result(0.0); 1170 for (int per = start; per <= end; ++per) 1171 result = calc->add(result, helper_ipmt(calc, rate, Value(per), nper, pv, Value(0.0), type)); 1172 1173 return result; 1174 } 1175 1176 1177 // 1178 // Function: CUMPRINC 1179 // 1180 Value func_cumprinc(valVector args, ValueCalc *calc, FuncExtra *) 1181 { 1182 const Value rate = args[0]; 1183 if (rate.asFloat() <= 0.0) 1184 return Value::errorVALUE(); 1185 const Value nper = args[1]; 1186 const int periods = nper.asInteger(); 1187 if (periods <= 0) 1188 return Value::errorVALUE(); 1189 const Value pv = args[2]; 1190 if (pv.asFloat() <= 0.0) 1191 return Value::errorVALUE(); 1192 const Value v1(calc->conv()->asInteger(args[3])); 1193 if (v1.isError()) 1194 return Value::errorVALUE(); 1195 const int start = v1.asInteger(); 1196 if (start <= 0 || start > periods) 1197 return Value::errorVALUE(); 1198 const Value v2(calc->conv()->asInteger(args[4])); 1199 if (v2.isError()) 1200 return Value::errorVALUE(); 1201 const int end = v2.asInteger(); 1202 if (end <= 0 || end < start || end > periods) 1203 return Value::errorVALUE(); 1204 const Value type(calc->conv()->asInteger(args[5])); 1205 if (type.isError()) 1206 return Value::errorVALUE(); 1207 1208 const Value pay = getPay(calc, rate, nper, pv, Value(0.0), type); 1209 const Value cumipmt = func_cumipmt(args, calc, 0); 1210 1211 return calc->sub(calc->mul(pay, Value(end - start + 1)), cumipmt); 1212 } 1213 1214 1215 // 1216 // Function: DB 1217 // 1218 // fixed-declining depreciation 1219 // 1220 Value func_db(valVector args, ValueCalc *calc, FuncExtra *) 1221 { 1222 // This function doesn't support extended datatypes, it simply 1223 // converts everything to double - because it does quite a bit 1224 // of computing, and, well, I'm lazy to convert it all (Tomas) 1225 double cost = numToDouble(calc->conv()->toFloat(args[0])); 1226 double salvage = numToDouble(calc->conv()->toFloat(args[1])); 1227 double life = numToDouble(calc->conv()->toFloat(args[2])); 1228 double period = numToDouble(calc->conv()->toFloat(args[3])); 1229 double month = 12; 1230 if (args.count() == 5) 1231 month = numToDouble(calc->conv()->toFloat(args[4])); 1232 1233 // sentinel check 1234 if (cost == 0 || life <= 0.0 || period == 0) 1235 return Value::errorNUM(); 1236 1237 if (calc->lower(calc->div(Value(salvage), Value(cost)), Value(0))) 1238 return Value::errorNUM(); 1239 1240 double rate = 1000 * (1 - pow((salvage / cost), (1 / life))); 1241 rate = floor(rate + 0.5) / 1000; 1242 1243 double total = cost * rate * month / 12; 1244 1245 if (period == 1) 1246 return Value(total); 1247 1248 for (int i = 1; i < life; ++i) 1249 if (i == period - 1) 1250 return Value(rate *(cost - total)); 1251 else total += rate * (cost - total); 1252 1253 return Value((cost - total) * rate *(12 - month) / 12); 1254 } 1255 1256 1257 // 1258 // Function: DDB 1259 // 1260 // depreciation per period 1261 // 1262 Value func_ddb(valVector args, ValueCalc *calc, FuncExtra *) 1263 { 1264 double cost = numToDouble(calc->conv()->toFloat(args[0])); 1265 double salvage = numToDouble(calc->conv()->toFloat(args[1])); 1266 double life = numToDouble(calc->conv()->toFloat(args[2])); 1267 double period = numToDouble(calc->conv()->toFloat(args[3])); 1268 double factor = 2; 1269 if (args.count() == 5) 1270 factor = numToDouble(calc->conv()->toFloat(args[4])); 1271 1272 if (cost < 0.0 || salvage < 0.0 || life <= 0.0 || period < 0.0 || factor < 0.0) 1273 return Value::errorVALUE(); 1274 1275 double result = 0.0; 1276 1277 if (factor >= life) 1278 // special case: amazingly gigantic depreciating rate 1279 result = (period > 1) ? 0 : (cost < salvage) ? 0 : cost - salvage; 1280 else { 1281 // depreciation is the value between two periods 1282 double invrate = (life - factor) / life; 1283 double current = (period == 1) ? invrate : pow(invrate, period); 1284 double previous = current / invrate; 1285 current *= cost; 1286 previous *= cost; 1287 result = previous - current; 1288 1289 // should not be more than the salvage 1290 if (current < salvage) 1291 result = previous - salvage; 1292 } 1293 1294 // can't be negative 1295 if (result < 0.0) 1296 result = 0.0; 1297 1298 return Value(result); 1299 } 1300 1301 1302 // 1303 // Function: DISC 1304 // 1305 Value func_disc(valVector args, ValueCalc *calc, FuncExtra *) 1306 { 1307 QDate settlement = calc->conv()->asDate(args[0]).asDate(calc->settings()); 1308 QDate maturity = calc->conv()->asDate(args[1]).asDate(calc->settings()); 1309 1310 // TODO sascha fix error value checking 1311 // // check dates 1312 // if ( settlement > maturity || ) 1313 // return Value(false); 1314 1315 Value par = args[2]; 1316 Value redemp = args[3]; 1317 1318 // check parameters 1319 if (settlement > maturity || redemp.asFloat() <= 0.0 || par.asFloat() <= 0.0) 1320 return Value(false); 1321 1322 int basis = 0; 1323 if (args.count() == 5) 1324 basis = calc->conv()->asInteger(args[4]).asInteger(); 1325 1326 /* double y = daysPerYear (settlement, basis); 1327 double d = daysBetweenDates (settlement, maturity, basis); 1328 1329 if ( y <= 0 || d <= 0 || basis < 0 || basis > 4 || calc->isZero (redemp) ) 1330 return Value(false);*/ 1331 1332 QDate date0 = calc->settings()->referenceDate(); // referenceDate 1333 1334 // res=(1-(price/redemption)/yearfrac) 1335 return Value((1.0 - par.asFloat() / redemp.asFloat()) / yearFrac(date0, settlement, maturity, basis)); 1336 } 1337 1338 1339 // 1340 // Function: DOLLARDE 1341 // 1342 Value func_dollarde(valVector args, ValueCalc *calc, FuncExtra *) 1343 { 1344 double dollarFrac = args[0].asFloat(); 1345 double frac = calc->conv()->asInteger(args[1]).asInteger(); 1346 1347 if (frac <= 0) 1348 return Value::errorVALUE(); 1349 1350 double fl; 1351 double res = modf(dollarFrac, &fl); 1352 1353 res /= frac; 1354 res *= pow(10.0, ceil(log10(frac))); 1355 res += fl; 1356 1357 return Value(res); 1358 } 1359 1360 1361 // 1362 // Function: DOLLARFR 1363 // 1364 Value func_dollarfr(valVector args, ValueCalc *calc, FuncExtra *) 1365 { 1366 double dollarFrac = args[0].asFloat(); 1367 double frac = calc->conv()->asInteger(args[1]).asInteger(); 1368 1369 if (frac <= 0) 1370 return Value::errorVALUE(); 1371 1372 double fl; 1373 double res = modf(dollarFrac, &fl); 1374 1375 res *= frac; 1376 res *= pow(10.0, -ceil(log10(frac))); 1377 res += fl; 1378 1379 return Value(res); 1380 } 1381 1382 1383 // 1384 // Function: DURATION 1385 // 1386 // 1387 // duration( rate, pv, fv ) 1388 // 1389 Value func_duration(valVector args, ValueCalc *calc, FuncExtra *) 1390 { 1391 Value rate = args[0]; 1392 Value pv = args[1]; 1393 Value fv = args[2]; 1394 1395 if (!calc->greater(rate, Value(0.0))) 1396 return Value::errorVALUE(); 1397 if (calc->isZero(fv) || calc->isZero(pv)) 1398 return Value::errorDIV0(); 1399 1400 if (calc->lower(calc->div(fv, pv), Value(0))) 1401 return Value::errorVALUE(); 1402 1403 // log(fv / pv) / log(1.0 + rate) 1404 return calc->div(calc->ln(calc->div(fv, pv)), 1405 calc->ln(calc->add(rate, Value(1.0)))); 1406 } 1407 1408 1409 // 1410 // Function: DURATION 1411 // 1412 // 1413 // duration( settlement, maturity, coup, yield, freq, [basis = 0] ) 1414 // 1415 Value func_duration_add(valVector args, ValueCalc *calc, FuncExtra *) 1416 { 1417 QDate settlement = calc->conv()->asDate(args[0]).asDate(calc->settings()); 1418 QDate maturity = calc->conv()->asDate(args[1]).asDate(calc->settings()); 1419 1420 double coup = numToDouble(calc->conv()->toFloat(args[2])); 1421 double yield = numToDouble(calc->conv()->toFloat(args[3])); 1422 int freq = calc->conv()->asInteger(args[4]).asInteger(); 1423 1424 int basis = 0; 1425 if (args.count() > 5) 1426 basis = calc->conv()->asInteger(args[3]).asInteger(); 1427 1428 // TODO add chk_freq 1429 if (coup < 0.0 || yield < 0.0) 1430 return Value::errorVALUE(); 1431 1432 QDate date0 = calc->settings()->referenceDate(); // referenceDate 1433 1434 valVector param; 1435 param.append(args[0]); 1436 param.append(args[1]); 1437 param.append(args[4]); 1438 param.append(Value(basis)); 1439 1440 int numOfCoups = Value(func_coupnum(param, calc, 0)).asInteger(); 1441 1442 debugSheetsFormula << "DURATION"; 1443 debugSheetsFormula << "numOfCoup =" << numOfCoups; 1444 1445 1446 return Value(duration(date0, settlement, maturity, coup, yield, freq, basis, numOfCoups)); 1447 } 1448 1449 1450 // 1451 // Function: effective 1452 // 1453 Value func_effective(valVector args, ValueCalc *calc, FuncExtra *) 1454 { 1455 // Returns effective interest rate given nominal rate and periods per year 1456 1457 Value nominal = args[0]; 1458 Value periods = args[1]; 1459 1460 // base = 1 + (nominal / periods) 1461 // result = pow (base, periods) - 1 1462 Value base = calc->add(calc->div(nominal, periods), 1); 1463 return calc->sub(calc->pow(base, periods), 1); 1464 } 1465 1466 1467 // 1468 // Function: EURO 1469 // 1470 Value func_euro(valVector args, ValueCalc *calc, FuncExtra *) 1471 { 1472 QString currency = calc->conv()->asString(args[0]).asString(); 1473 double result = helper_eurofactor(currency); 1474 if (result < 0) 1475 return Value::errorNUM(); 1476 1477 return Value(result); 1478 } 1479 1480 1481 // 1482 // EUROCONVERT(number,source,target) 1483 // 1484 Value func_euroconvert(valVector args, ValueCalc *calc, FuncExtra *) 1485 { 1486 double number = numToDouble(calc->conv()->toFloat(args[0])); 1487 QString source = calc->conv()->asString(args[1]).asString(); 1488 QString target = calc->conv()->asString(args[2]).asString(); 1489 1490 double factor1 = helper_eurofactor(source); 1491 double factor2 = helper_eurofactor(target); 1492 1493 if (factor1 < 0) 1494 return Value::errorNUM(); 1495 if (factor2 < 0) 1496 return Value::errorNUM(); 1497 1498 double result = number * factor2 / factor1; 1499 1500 return Value(result); 1501 } 1502 1503 1504 // 1505 // Function: FV 1506 // 1507 // Returns future value, given current value, interest rate and time 1508 // 1509 Value func_fv(valVector args, ValueCalc *calc, FuncExtra *) 1510 { 1511 Value rate = args[0]; 1512 Value nper = args[1]; 1513 Value pmt = args[2]; 1514 1515 // defaults 1516 Value pv(0.0); 1517 int type = 0; 1518 1519 if (args.count() > 3) 1520 pv = Value(calc->conv()->asFloat(args[3]).asFloat()); 1521 1522 if (args.count() == 5) 1523 type = calc->conv()->asInteger(args[4]).asInteger(); 1524 1525 //TODO check payType 1526 1527 Value pvif = Value(pow1p(rate.asFloat(), nper.asFloat())); 1528 Value fvifa = calc_fvifa(calc, rate, nper); 1529 1530 Value res(calc->mul(Value(-1), calc->add(calc->mul(pv, pvif), calc->mul(pmt, calc->mul(calc->add(Value(1), calc->mul(rate, type)), fvifa))))); 1531 1532 return (res); 1533 // present * pow (1 + interest, periods) 1534 // return calc->mul (present, calc->pow (calc->add (interest, 1), periods)); 1535 } 1536 1537 // 1538 // Function: FVSCHEDULE 1539 // 1540 // Returns future value 1541 // 1542 Value func_fvschedule(valVector args, ValueCalc *calc, FuncExtra *) 1543 { 1544 Value pv = args[0]; 1545 Value schedule = args[1]; 1546 1547 int n = schedule.count(); 1548 int i; 1549 1550 Value v; 1551 Value res(pv); 1552 1553 for (i = 0; i < n; ++i) { 1554 v = args[1].element(i); 1555 res = Value(calc->mul(res, calc->add(Value(1), v))); 1556 } 1557 1558 return (res); 1559 } 1560 1561 1562 // 1563 // Function: FV_annuity 1564 // 1565 Value func_fv_annuity(valVector args, ValueCalc *calc, FuncExtra *) 1566 { 1567 /* Returns future value of an annuity or cash flow, given payment, interest 1568 rate and periods */ 1569 1570 Value amount = args[0]; 1571 Value interest = args[1]; 1572 Value periods = args[2]; 1573 1574 // pw = pow (1 + interest, periods) 1575 // result = amount * ((pw - 1) / interest) 1576 Value pw = calc->pow(calc->add(interest, 1), periods); 1577 return calc->mul(amount, calc->div(calc->sub(pw, 1), interest)); 1578 } 1579 1580 1581 // 1582 // Function: INTRATE 1583 // 1584 Value func_intrate(valVector args, ValueCalc *calc, FuncExtra *) 1585 { 1586 QDate settlement = calc->conv()->asDate(args[0]).asDate(calc->settings()); 1587 QDate maturity = calc->conv()->asDate(args[1]).asDate(calc->settings()); 1588 1589 Value invest = args[2]; 1590 Value redemption = args[3]; 1591 1592 int basis = 0; 1593 if (args.count() == 5) 1594 basis = calc->conv()->asInteger(args[4]).asInteger(); 1595 1596 double d = daysBetweenDates(settlement, maturity, basis); 1597 double y = daysPerYear(settlement, basis); 1598 1599 if (d <= 0 || y <= 0 || calc->isZero(invest) || basis < 0 || basis > 4) 1600 return Value::errorVALUE(); 1601 1602 // (redemption - invest) / invest * (y / d) 1603 return calc->mul(calc->div(calc->sub(redemption, invest), invest), y / d); 1604 } 1605 1606 1607 // 1608 // Function: IPMT 1609 // 1610 Value func_ipmt(valVector args, ValueCalc *calc, FuncExtra *) 1611 { 1612 Value rate = args[0]; 1613 Value per = args[1]; 1614 Value nper = args[2]; 1615 Value pv = args[3]; 1616 1617 Value fv = Value(0.0); 1618 Value type = Value(0); 1619 if (args.count() > 4) fv = args[4]; 1620 if (args.count() == 6) type = args[5]; 1621 1622 return helper_ipmt(calc, rate, per, nper, pv, fv, type); 1623 } 1624 1625 static double irrResult(Value sec, ValueCalc *calc, double rate) 1626 { 1627 double res = 0; 1628 for (unsigned i = 0; i < sec.count(); ++i) { 1629 double val = calc->conv()->asFloat(sec.element(i)).asFloat(); 1630 res += val / pow(1.0 + rate, double(i)); 1631 } 1632 return res; 1633 } 1634 1635 static double irrResultDerive(Value sec, ValueCalc *calc, double rate) 1636 { 1637 double res = 0; 1638 for (unsigned i = 0; i < sec.count(); ++i) { 1639 double val = calc->conv()->asFloat(sec.element(i)).asFloat(); 1640 res += -double(i) * val / pow(1.0 + rate, double(i + 1)); 1641 } 1642 return res; 1643 } 1644 1645 // 1646 // Function: IRR 1647 // 1648 Value func_irr(valVector args, ValueCalc *calc, FuncExtra *) 1649 { 1650 static const double maxEpsilon = 1e-10; 1651 static const int maxIter = 50; 1652 1653 Value seq = args[0]; 1654 1655 double rate = 0.1; 1656 if (args.count() > 1) rate = calc->conv()->asFloat(args[1]).asFloat(); 1657 1658 bool contLoop; 1659 int i = 0; 1660 do { 1661 double newRate = rate - irrResult(seq, calc, rate) / irrResultDerive(seq, calc, rate); 1662 double rateEpsilon = fabs(newRate - rate); 1663 rate = newRate; 1664 contLoop = (rateEpsilon > maxEpsilon) && (fabs(rate) > maxEpsilon); 1665 } while (contLoop && (++i < maxIter)); 1666 1667 return Value(rate); 1668 } 1669 1670 // 1671 // Function: ISPMT 1672 // 1673 Value func_ispmt(valVector args, ValueCalc *calc, FuncExtra *) 1674 { 1675 Value rate = args[0]; 1676 Value per = args[1]; 1677 Value nper = args[2]; 1678 Value pv = args[3]; 1679 1680 if (calc->lower(per, Value(1)) || calc->greater(per, nper)) 1681 return Value::errorVALUE(); 1682 1683 // d = -pv * rate 1684 Value d = calc->mul(calc->mul(pv, Value(-1)), rate); 1685 1686 // d - (d / nper * per) 1687 return calc->sub(d, calc->mul(calc->div(d, nper), per)); 1688 } 1689 1690 1691 // 1692 // Function: MDURATION 1693 // 1694 // 1695 // duration( settlement, maturity, coup, yield, freq, [basis = 0] ) 1696 // 1697 Value func_mduration(valVector args, ValueCalc *calc, FuncExtra *) 1698 { 1699 QDate settlement = calc->conv()->asDate(args[0]).asDate(calc->settings()); 1700 QDate maturity = calc->conv()->asDate(args[1]).asDate(calc->settings()); 1701 1702 double coup = numToDouble(calc->conv()->toFloat(args[2])); 1703 double yield = numToDouble(calc->conv()->toFloat(args[3])); 1704 int freq = calc->conv()->asInteger(args[4]).asInteger(); 1705 1706 int basis = 0; 1707 if (args.count() > 5) 1708 basis = calc->conv()->asInteger(args[3]).asInteger(); 1709 1710 // TODO add chk_freq 1711 if (coup < 0.0 || yield < 0.0) 1712 return Value::errorVALUE(); 1713 1714 QDate date0 = calc->settings()->referenceDate(); // referenceDate 1715 1716 valVector param; 1717 param.append(args[0]); 1718 param.append(args[1]); 1719 param.append(args[4]); 1720 param.append(Value(basis)); 1721 1722 int numOfCoups = Value(func_coupnum(param, calc, 0)).asInteger(); 1723 1724 double res = duration(date0, settlement, maturity, coup, yield, freq, basis, numOfCoups); 1725 res /= 1.0 + (yield / double(freq)); 1726 1727 return Value(res); 1728 } 1729 1730 1731 // 1732 // Function: MIRR 1733 // 1734 Value func_mirr(valVector args, ValueCalc *calc, FuncExtra *) 1735 { 1736 long double inv = calc->conv()->asFloat(args[1]).asFloat(); 1737 long double reInvRate = calc->conv()->asFloat(args[2]).asFloat(); 1738 1739 long double npv_pos, npv_neg; 1740 Value v; 1741 int n = args[0].count(); 1742 int i; 1743 1744 for (i = 0, npv_pos = npv_neg = 0; i < n; ++i) { 1745 v = args[0].element(i); 1746 if (v.asFloat() >= 0) 1747 npv_pos += v.asFloat() / pow1p(reInvRate, i); 1748 else 1749 npv_neg += v.asFloat() / pow1p(inv, i); 1750 } 1751 1752 if (npv_neg == 0 || npv_pos == 0 || reInvRate <= -1.0l) 1753 return Value::errorVALUE(); 1754 1755 long double res = std::pow((-npv_pos * pow1p(reInvRate, n)) / (npv_neg * (1 + reInvRate)), (1.0l / (n - 1))) - 1.0l; 1756 1757 return Value(res); 1758 } 1759 1760 1761 // 1762 // Function: level_coupon 1763 // 1764 Value func_level_coupon(valVector args, ValueCalc *calc, FuncExtra *) 1765 { 1766 // Returns effective interest rate given nominal rate and periods per year 1767 Value face = args[0]; 1768 Value coupon_rate = args[1]; 1769 Value coupon_year = args[2]; 1770 Value years = args[3]; 1771 Value market_rate = args[4]; 1772 1773 Value coupon, interest, pw, pv_annuity; 1774 // coupon = coupon_rate * face / coupon_year 1775 // interest = market_rate / coupon_year 1776 // pw = pow(1 + interest, years * coupon_year) 1777 // pv_annuity = (1 - 1 / pw) / interest 1778 // result = coupon * pv_annuity + face / pw 1779 coupon = calc->mul(coupon_rate, calc->div(face, coupon_year)); 1780 interest = calc->div(market_rate, coupon_year); 1781 pw = calc->pow(calc->add(interest, Value(1)), calc->mul(years, coupon_year)); 1782 pv_annuity = calc->div(calc->sub(Value(1), calc->div(Value(1), pw)), interest); 1783 return calc->add(calc->mul(coupon, pv_annuity), calc->div(face, pw)); 1784 } 1785 1786 1787 // 1788 // Function: nominal 1789 // 1790 Value func_nominal(valVector args, ValueCalc *calc, FuncExtra *) 1791 { 1792 Value effective = args[0]; 1793 Value periods = args[1]; 1794 1795 // sentinel checks 1796 if (calc->isZero(periods)) 1797 return Value::errorDIV0(); 1798 if (!calc->greater(periods, Value(0.0))) 1799 return Value::errorVALUE(); 1800 if (calc->isZero(effective)) 1801 return Value::errorVALUE(); 1802 if (!calc->greater(effective, Value(0.0))) 1803 return Value::errorVALUE(); 1804 1805 // pw = pow (effective + 1, 1 / periods) 1806 // result = periods * (pw - 1); 1807 Value pw; 1808 pw = calc->pow(calc->add(effective, Value(1)), calc->div(Value(1), periods)); 1809 return calc->mul(periods, calc->sub(pw, Value(1))); 1810 } 1811 1812 1813 // 1814 // Function: NPER 1815 // 1816 Value func_nper(valVector args, ValueCalc *calc, FuncExtra *) 1817 { 1818 double rate = calc->conv()->asFloat(args[0]).asFloat(); 1819 double pmt = calc->conv()->asFloat(args[1]).asFloat(); 1820 double pv = calc->conv()->asFloat(args[2]).asFloat(); 1821 1822 // defaults 1823 double fv = 0.0; 1824 double type = 0; 1825 1826 // opt. params 1827 if (args.count() > 3) fv = calc->conv()->asFloat(args[3]).asFloat(); 1828 if (args.count() == 5) type = calc->conv()->asFloat(args[4]).asFloat(); 1829 1830 // if rate is 0, then NPER solves this 1831 // PV = -FV -( Payment*NPER ) 1832 if (rate == 0.0) 1833 return Value(-(pv + fv) / pmt); 1834 1835 if (type > 0) 1836 return Value(log(-(rate*fv - pmt*(1.0 + rate)) / (rate*pv + pmt*(1.0 + rate))) / log(1.0 + rate)); 1837 else 1838 return Value(log(-(rate*fv - pmt) / (rate*pv + pmt)) / log(1.0 + rate)); 1839 } 1840 1841 1842 // 1843 // NPV 1844 // 1845 Value func_npv(valVector args, ValueCalc* calc, FuncExtra*) 1846 { 1847 Value result(Value::Array); 1848 result.setElement(0, 0, Value(0.0)); // actual result 1849 result.setElement(1, 0, Value(1.0)); // counter 1850 if (args.count() == 2) { 1851 Value vector = args[1]; // may be an array 1852 calc->arrayWalk(vector, result, awNpv, calc->conv()->asFloat(args[0])); 1853 } else { 1854 valVector vector = args.mid(1); 1855 calc->arrayWalk(vector, result, awNpv, calc->conv()->asFloat(args[0])); 1856 } 1857 return result.element(0, 0); 1858 } 1859 1860 static double date_ratio(const QDate& d1, const QDate& d2, const QDate& d3, const CoupSettings& conv) 1861 { 1862 QDate next = coup_cd(d1, d3, conv.frequency, conv.eom, true); 1863 QDate prev = coup_cd(d1, d3, conv.frequency, conv.eom, false); 1864 1865 if (next >= d2) { 1866 return daysBetweenBasis(d1, d2, conv.basis) / 1867 coupdays(prev, next, conv); 1868 } 1869 1870 double res = daysBetweenBasis(d1, next, conv.basis) / 1871 coupdays(prev, next, conv); 1872 1873 while (true) { 1874 prev = next; 1875 next = next.addMonths(12 / conv.frequency); 1876 //if (!next.isValid()) 1877 // 1878 if (next >= d2) { 1879 res += daysBetweenBasis(prev, d2, conv.basis) / 1880 coupdays(prev, next, conv); 1881 return res; 1882 } 1883 res += 1; 1884 } 1885 } 1886 1887 // 1888 // ODDLPRICE 1889 // 1890 Value func_oddlprice(valVector args, ValueCalc *calc, FuncExtra *) 1891 { 1892 QDate settlement = calc->conv()->asDate(args[0]).asDate(calc->settings()); 1893 QDate maturity = calc->conv()->asDate(args[1]).asDate(calc->settings()); 1894 QDate last = calc->conv()->asDate(args[2]).asDate(calc->settings()); 1895 double rate = calc->conv()->asFloat(args[3]).asFloat(); 1896 double yield = calc->conv()->asFloat(args[4]).asFloat(); 1897 double redemp = calc->conv()->asFloat(args[5]).asFloat(); 1898 double freq = calc->conv()->asFloat(args[6]).asFloat(); 1899 1900 // opt. basis 1901 int basis = 0; 1902 if (args.count() > 7) 1903 basis = calc->conv()->asInteger(args[7]).asInteger(); 1904 1905 CoupSettings conv; 1906 conv.basis = static_cast<CoupBasis>(basis); 1907 conv.frequency = freq; 1908 conv.eom = true; 1909 1910 // debugSheetsFormula<<"ODDLPRICE"; 1911 // debugSheetsFormula<<"settlement ="<<settlement<<" maturity="<<maturity<<" last="<<last<<" rate="<<rate<<" yield="<<yield<<" redemp="<<redemp<<" freq="<<freq<<" basis="<<basis; 1912 1913 // TODO check frequency 1914 if (yield <= 0.0 || rate <= 0.0 || maturity <= settlement || settlement <= last) 1915 return Value::errorVALUE(); 1916 1917 QDate d = last; 1918 do { 1919 d = d.addMonths(12 / conv.frequency); 1920 } while (d.isValid() && d < maturity); 1921 1922 double x1 = date_ratio(last, settlement, d, conv); 1923 double x2 = date_ratio(last, maturity, d, conv); 1924 double x3 = date_ratio(settlement, maturity, d, conv); 1925 1926 return Value((redemp * conv.frequency + 1927 100 * rate * (x2 - x1 * (1 + yield * x3 / conv.frequency))) / 1928 (yield * x3 + conv.frequency)); 1929 } 1930 1931 1932 // 1933 // ODDLYIELD 1934 // 1935 Value func_oddlyield(valVector args, ValueCalc *calc, FuncExtra *) 1936 { 1937 QDate settlement = calc->conv()->asDate(args[0]).asDate(calc->settings()); 1938 QDate maturity = calc->conv()->asDate(args[1]).asDate(calc->settings()); 1939 QDate last = calc->conv()->asDate(args[2]).asDate(calc->settings()); 1940 double rate = calc->conv()->asFloat(args[3]).asFloat(); 1941 double price = calc->conv()->asFloat(args[4]).asFloat(); 1942 double redemp = calc->conv()->asFloat(args[5]).asFloat(); 1943 double freq = calc->conv()->asFloat(args[6]).asFloat(); 1944 1945 // opt. basis 1946 int basis = 0; 1947 if (args.count() > 7) 1948 basis = calc->conv()->asInteger(args[7]).asInteger(); 1949 1950 CoupSettings conv; 1951 conv.basis = static_cast<CoupBasis>(basis); 1952 conv.frequency = freq; 1953 conv.eom = true; 1954 1955 // debugSheetsFormula<<"ODDLYIELD"; 1956 // debugSheetsFormula<<"settlement ="<<settlement<<" maturity="<<maturity<<" last="<<last<<" rate="<<rate<<" price="<<price<<" redemp="<<redemp<<" freq="<<freq<<" basis="<<basis; 1957 1958 // TODO check frequency 1959 if (rate < 0.0 || price <= 0.0 || maturity <= settlement || settlement <= last) 1960 return Value::errorVALUE(); 1961 1962 1963 QDate d = last; 1964 do { 1965 d = d.addMonths(12 / conv.frequency); 1966 } while (d.isValid() && d < maturity); 1967 1968 double x1 = date_ratio(last, settlement, d, conv); 1969 double x2 = date_ratio(last, maturity, d, conv); 1970 double x3 = date_ratio(settlement, maturity, d, conv); 1971 1972 1973 return Value((conv.frequency * (redemp - price) + 100 * rate * (x2 - x1)) / 1974 (x3 * price + 100 * rate * x1 * x3 / conv.frequency)); 1975 } 1976 1977 1978 // 1979 // Function: PMT 1980 // 1981 Value func_pmt(valVector args, ValueCalc *calc, FuncExtra *) 1982 { 1983 Value rate = args[0]; 1984 Value nper = args[1]; 1985 Value pv = args[2]; 1986 Value fv = Value(0.0); 1987 Value type = Value(0); 1988 if (args.count() > 3) fv = args[3]; 1989 if (args.count() == 5) type = args[4]; 1990 1991 return getPay(calc, rate, nper, pv, fv, type); 1992 } 1993 1994 1995 // 1996 // Function: PPMT 1997 // 1998 // Uses IPMT. 1999 // 2000 Value func_ppmt(valVector args, ValueCalc *calc, FuncExtra *) 2001 { 2002 // Docs partly copied from OO. 2003 // 2004 // PPMT(Rate;Period;NPER;PV;FV;Type) 2005 // 2006 // Rate is the periodic interest rate. 2007 // Period is the amortizement period. P=1 for the first and P=NPER for the last period. 2008 // NPER is the total number of periods during which annuity is paid. 2009 // PV is the present value in the sequence of payments. 2010 // FV (optional) is the desired (future) value. 2011 // Type (optional) defines the due date. F=1 for payment at the beginning of a period and F=0 for payment at the end of a period. 2012 // 2013 2014 Value rate = args[0]; 2015 Value per = args[1]; 2016 Value nper = args[2]; 2017 Value pv = args[3]; 2018 2019 // defaults 2020 Value fv = Value(0.0); 2021 Value type = Value(0); 2022 2023 if (args.count() > 4) fv = args[4]; 2024 if (args.count() == 6) type = args[5]; 2025 2026 debugSheets << "Type=" << type; 2027 2028 Value pay = getPay(calc, rate, nper, pv, fv, type); 2029 Value ipmt = func_ipmt(args, calc, 0); 2030 return calc->sub(pay, ipmt); 2031 } 2032 2033 2034 // 2035 // PRICEMAT 2036 // 2037 Value func_pricemat(valVector args, ValueCalc *calc, FuncExtra *) 2038 { 2039 QDate settlement = calc->conv()->asDate(args[0]).asDate(calc->settings()); 2040 QDate maturity = calc->conv()->asDate(args[1]).asDate(calc->settings()); 2041 QDate issue = calc->conv()->asDate(args[2]).asDate(calc->settings()); 2042 double rate = calc->conv()->asFloat(args[3]).asFloat(); 2043 double yield = calc->conv()->asFloat(args[4]).asFloat(); 2044 2045 // opt. basis 2046 int basis = 0; 2047 if (args.count() > 5) 2048 basis = calc->conv()->asInteger(args[5]).asInteger(); 2049 2050 //debugSheetsFormula<<"PRICEMAT"; 2051 //debugSheetsFormula<<"settlement ="<<settlement<<" maturity="<<maturity<<" issue="<<issue<<" rate="<<rate<<" yield="<<yield<<" basis="<<basis; 2052 2053 if (rate < 0.0 || yield < 0.0 || settlement >= maturity) 2054 return Value::errorVALUE(); 2055 2056 long double y = daysPerYear(settlement, basis); 2057 if (!y) return Value::errorVALUE(); 2058 long double issMat = daysBetweenDates(issue, maturity, basis) / y; 2059 long double issSet = daysBetweenDates(issue, settlement, basis) / y; 2060 long double setMat = daysBetweenDates(settlement, maturity, basis) / y; 2061 2062 long double res = 1.0l + issMat * rate; 2063 res /= 1.0l + setMat * yield; 2064 res -= issSet * rate; 2065 res *= 100.0l; 2066 2067 return Value(res); 2068 } 2069 2070 2071 // 2072 // Function: PV 2073 // 2074 // Returns present value, given future value, interest rate and years 2075 // 2076 Value func_pv(valVector args, ValueCalc *calc, FuncExtra *) 2077 { 2078 double rate = calc->conv()->asFloat(args[0]).asFloat(); 2079 double nper = calc->conv()->asFloat(args[1]).asFloat(); 2080 double pmt = calc->conv()->asFloat(args[2]).asFloat(); 2081 2082 double fv = 0; 2083 int type = 0; 2084 2085 if (args.count() > 3) 2086 fv = calc->conv()->asFloat(args[3]).asFloat(); 2087 if (args.count() > 4) 2088 type = calc->conv()->asInteger(args[4]).asInteger(); 2089 // TODO error Value checking for type 2090 2091 2092 double pvif = pow(1 + rate, nper); 2093 double fvifa = (pvif - 1) / rate; 2094 2095 if (pvif == 0) 2096 return Value::errorDIV0(); 2097 2098 double res = (-fv - pmt * (1.0 + rate * type) * fvifa) / pvif; 2099 2100 return Value(res); 2101 } 2102 2103 2104 // 2105 // Function: PV_annuity 2106 // 2107 Value func_pv_annuity(valVector args, ValueCalc *calc, FuncExtra *) 2108 { 2109 Value amount = args[0]; 2110 Value interest = args[1]; 2111 Value periods = args[2]; 2112 2113 // recpow = 1 / pow (1 + interest, periods) 2114 // result = amount * (1 - recpow) / interest; 2115 Value recpow; 2116 recpow = calc->div(Value(1), calc->pow(calc->add(interest, Value(1)), periods)); 2117 return calc->mul(amount, calc->div(calc->sub(Value(1), recpow), interest)); 2118 } 2119 2120 2121 // 2122 // Function: RATE 2123 // 2124 Value func_rate(valVector args, ValueCalc *calc, FuncExtra *) 2125 { 2126 const Value nper = args[0]; 2127 double fNper = calc->conv()->asFloat(nper).asFloat(); 2128 double fPayment = calc->conv()->asFloat(args[1]).asFloat(); 2129 double fPv = calc->conv()->asFloat(args[2]).asFloat(); 2130 double fFv = (args.count() > 3) ? calc->conv()->asFloat(args[3]).asFloat() : 0; 2131 double fPayType = (args.count() > 4) ? calc->conv()->asFloat(args[4]).asFloat() : 0; 2132 double fGuess = (args.count() > 5) ? calc->conv()->asFloat(args[5]).asFloat() : 0.1; 2133 2134 if (fNper <= 0.0) 2135 return Value::errorVALUE(); 2136 2137 bool bValid = true, bFound = false; 2138 double fX, fXnew, fTerm, fTermDerivation; 2139 double fGeoSeries, fGeoSeriesDerivation; 2140 const unsigned short nIterationsMax = 150; 2141 unsigned short nCount = 0; 2142 const double fEpsilonSmall = 1.0E-14; 2143 const double fEpsilon = 1.0E-7; 2144 2145 fFv -= fPayment * fPayType; 2146 fPv += fPayment * fPayType; 2147 if (nper.isInteger()) { 2148 fX = fGuess; 2149 double fPowN, fPowNminus1; 2150 while (!bFound && nCount < nIterationsMax) { 2151 fPowNminus1 = pow( 1.0+fX, fNper-1.0); 2152 fPowN = fPowNminus1 * (1.0+fX); 2153 if (calc->approxEqual(Value(fabs(fX)), Value(0.0))) { 2154 fGeoSeries = fNper; 2155 fGeoSeriesDerivation = fNper * (fNper-1.0)/2.0; 2156 } else { 2157 fGeoSeries = (fPowN-1.0)/fX; 2158 fGeoSeriesDerivation = fNper * fPowNminus1 / fX - fGeoSeries / fX; 2159 } 2160 fTerm = fFv + fPv *fPowN+ fPayment * fGeoSeries; 2161 fTermDerivation = fPv * fNper * fPowNminus1 + fPayment * fGeoSeriesDerivation; 2162 if (fabs(fTerm) < fEpsilonSmall) { 2163 bFound = true; 2164 } else { 2165 if (calc->approxEqual(Value(fabs(fTermDerivation)), Value(0.0))) 2166 fXnew = fX + 1.1 * fEpsilon; 2167 else 2168 fXnew = fX - fTerm / fTermDerivation; 2169 ++nCount; 2170 bFound = (fabs(fXnew - fX) < fEpsilon); 2171 fX = fXnew; 2172 } 2173 } 2174 bValid =(fX >=-1.0); 2175 } else { 2176 fX = (fGuess < -1.0) ? -1.0 : fGuess; 2177 while (bValid && !bFound && nCount < nIterationsMax) { 2178 if (calc->approxEqual(Value(fabs(fX)), Value(0.0))) { 2179 fGeoSeries = fNper; 2180 fGeoSeriesDerivation = fNper * (fNper-1.0)/2.0; 2181 } else { 2182 fGeoSeries = (pow( 1.0+fX, fNper) - 1.0) / fX; 2183 fGeoSeriesDerivation = fNper * pow( 1.0+fX, fNper-1.0) / fX - fGeoSeries / fX; 2184 } 2185 fTerm = fFv + fPv *pow(1.0 + fX,fNper)+ fPayment * fGeoSeries; 2186 fTermDerivation = fPv * fNper * pow(1.0+fX, fNper-1.0) + fPayment * fGeoSeriesDerivation; 2187 if (fabs(fTerm) < fEpsilonSmall) { 2188 bFound = true; 2189 } else { 2190 if (calc->approxEqual(Value(fabs(fTermDerivation)), Value(0.0))) 2191 fXnew = fX + 1.1 * fEpsilon; 2192 else 2193 fXnew = fX - fTerm / fTermDerivation; 2194 ++nCount; 2195 bFound = (fabs(fXnew - fX) < fEpsilon); 2196 fX = fXnew; 2197 bValid = (fX >= -1.0); 2198 } 2199 } 2200 } 2201 fGuess = fX; 2202 // ODF specs do not say that we should return an error in that case 2203 //if (!bValid || !bFound) return Value::errorVALUE(); 2204 return Value(fGuess); 2205 } 2206 2207 2208 // 2209 // Function: RECEIVED 2210 // 2211 Value func_received(valVector args, ValueCalc *calc, FuncExtra *) 2212 { 2213 QDate settlement = calc->conv()->asDate(args[0]).asDate(calc->settings()); 2214 QDate maturity = calc->conv()->asDate(args[1]).asDate(calc->settings()); 2215 2216 Value investment = args[2]; 2217 Value discount = args[3]; 2218 2219 int basis = 0; 2220 if (args.count() == 5) 2221 basis = calc->conv()->asInteger(args[4]).asInteger(); 2222 2223 double d = daysBetweenDates(settlement, maturity, basis); 2224 double y = daysPerYear(settlement, basis); 2225 2226 if (d <= 0 || y <= 0 || basis < 0 || basis > 4) 2227 return Value(false); 2228 2229 // 1.0 - ( discount * d / y ) 2230 Value x = calc->sub(Value(1.0), (calc->mul(discount, d / y))); 2231 2232 if (calc->isZero(x)) 2233 return Value::errorVALUE(); 2234 return calc->div(investment, x); 2235 } 2236 2237 2238 // 2239 // Function: RRI 2240 // 2241 Value func_rri(valVector args, ValueCalc *calc, FuncExtra *) 2242 { 2243 double p = calc->conv()->asFloat(args[0]).asFloat(); 2244 double pv = calc->conv()->asFloat(args[1]).asFloat(); 2245 double fv = calc->conv()->asFloat(args[2]).asFloat(); 2246 2247 // constraints N>0 2248 if (p < 1) 2249 return Value::errorVALUE(); 2250 2251 double res = pow((fv / pv), 1 / p) - 1; 2252 return Value(res); 2253 } 2254 2255 2256 // 2257 // Function: SLN 2258 // 2259 // straight-line depreciation for a single period 2260 // 2261 Value func_sln(valVector args, ValueCalc *calc, FuncExtra *) 2262 { 2263 Value cost = args[0]; 2264 Value salvage_value = args[1]; 2265 Value life = args[2]; 2266 2267 // sentinel check 2268 if (!calc->greater(life, Value(0.0))) 2269 return Value::errorVALUE(); 2270 2271 // (cost - salvage_value) / life 2272 return calc->div(calc->sub(cost, salvage_value), life); 2273 } 2274 2275 2276 // 2277 // Function: SYD 2278 // 2279 // sum-of-years digits depreciation 2280 // 2281 Value func_syd(valVector args, ValueCalc *calc, FuncExtra *) 2282 { 2283 Value cost = args[0]; 2284 Value salvage_value = args[1]; 2285 Value life = args[2]; 2286 Value period = args[3]; 2287 2288 // sentinel check 2289 if (!calc->greater(life, Value(0.0))) 2290 return Value::errorVALUE(); 2291 2292 // v1 = cost - salvage_value 2293 // v2 = life - period + 1 2294 // v3 = life * (life + 1.0) 2295 // result = (v1 * v2 * 2) / v3 2296 Value v1, v2, v3; 2297 v1 = calc->sub(cost, salvage_value); 2298 v2 = calc->add(calc->sub(life, period), 1); 2299 v3 = calc->mul(life, calc->add(life, 1.0)); 2300 return calc->div(calc->mul(calc->mul(v1, v2), 2), v3); 2301 } 2302 2303 2304 // 2305 // Function: TBILLEQ 2306 // 2307 Value func_tbilleq(valVector args, ValueCalc *calc, FuncExtra *) 2308 { 2309 QDate settlement = calc->conv()->asDate(args[0]).asDate(calc->settings()); 2310 QDate maturity = calc->conv()->asDate(args[1]).asDate(calc->settings()); 2311 double discount = calc->conv()->asFloat(args[2]).asFloat(); 2312 2313 maturity = maturity.addDays(1); 2314 int days = days360(settlement, maturity, false); // false -> US 2315 2316 if (settlement >= maturity || discount <= 0.0 || days > 360) 2317 return Value::errorVALUE(); 2318 2319 double res = (365 * discount) / (360 - (discount * double(days))); 2320 2321 return Value(res); 2322 } 2323 2324 2325 // 2326 // Function: TBILLPRICE 2327 // 2328 Value func_tbillprice(valVector args, ValueCalc *calc, FuncExtra *) 2329 { 2330 QDate settlement = calc->conv()->asDate(args[0]).asDate(calc->settings()); 2331 QDate maturity = calc->conv()->asDate(args[1]).asDate(calc->settings()); 2332 Value discount = args[2]; 2333 2334 QDate date0 = calc->settings()->referenceDate(); // referenceDate 2335 2336 double fraction = yearFrac(date0, settlement, maturity.addDays(1), 0); // basis: USA 30/360 2337 double dummy; 2338 2339 if (modf(fraction, &dummy) == 0.0) 2340 return Value::errorVALUE(); 2341 2342 // double days = settlement.daysTo( maturity ); 2343 // TODO error value checking 2344 // if (settlement > maturity || calc->lower (discount, Value(0)) || days > 265) 2345 // return Value::errorVALUE(); 2346 2347 return Value(100.0*(1.0 - discount.asFloat()*fraction)); 2348 } 2349 2350 2351 // 2352 // Function: TBILLYIELD 2353 // 2354 Value func_tbillyield(valVector args, ValueCalc *calc, FuncExtra *) 2355 { 2356 QDate settlement = calc->conv()->asDate(args[0]).asDate(calc->settings()); 2357 QDate maturity = calc->conv()->asDate(args[1]).asDate(calc->settings()); 2358 double price = calc->conv()->asFloat(args[2]).asFloat(); 2359 2360 double days = days360(settlement, maturity, false); // false -> US 2361 ++days; 2362 2363 if (settlement >= maturity || days > 360 || price <= 0.0) 2364 return Value::errorVALUE(); 2365 2366 double res = 100.0; 2367 res /= price; 2368 res--; 2369 res /= days; 2370 res *= 360.0; 2371 2372 return Value(res); 2373 } 2374 2375 2376 // 2377 // Function: VDB 2378 // 2379 // VDB( cost; salvage; life; startPeriod; endPeriod [; depreciation-factor = 2 [; straight-line depreciation = TRUE ] ) 2380 // 2381 Value func_vdb(valVector args, ValueCalc *calc, FuncExtra *) 2382 { 2383 double cost = calc->conv()->asFloat(args[0]).asFloat(); 2384 double salvage = calc->conv()->asFloat(args[1]).asFloat(); 2385 double life = calc->conv()->asFloat(args[2]).asFloat(); 2386 double startPeriod = calc->conv()->asFloat(args[3]).asFloat(); 2387 double endPeriod = calc->conv()->asFloat(args[4]).asFloat(); 2388 2389 // defaults 2390 double depreciationFactor = 2; 2391 bool flag = false; 2392 2393 // opt. parameter 2394 if (args.count() > 6) 2395 flag = calc->conv()->asInteger(args[6]).asInteger(); 2396 if (args.count() >= 5) 2397 depreciationFactor = calc->conv()->asFloat(args[5]).asFloat(); 2398 2399 // check if parameters are valid 2400 if (cost < 0.0 || endPeriod < startPeriod || endPeriod > life || cost < 0.0 || salvage > cost || depreciationFactor <= 0.0) 2401 return Value::errorVALUE(); 2402 2403 // calc loop start and end 2404 double intStart = floor(startPeriod); 2405 double intEnd = ceil(endPeriod); 2406 unsigned long loopStart = (unsigned long) intStart; 2407 unsigned long loopEnd = (unsigned long) intEnd; 2408 2409 double res = 0.0; 2410 2411 if (flag) { 2412 // no straight-line depreciation 2413 for (unsigned long i = loopStart + 1; i <= loopEnd; ++i) { 2414 double term = vdbGetGDA(cost, salvage, life, (double) i, depreciationFactor); 2415 2416 // 2417 if (i == loopStart + 1) 2418 term *= (fmin(endPeriod, intStart + 1.0) - startPeriod); 2419 else if (i == loopEnd) 2420 term *= (endPeriod + 1.0 - intEnd); 2421 2422 res += term; 2423 } 2424 } else { 2425 double life1 = life; 2426 double part; 2427 2428 if (startPeriod != floor(startPeriod)) { 2429 if (depreciationFactor > 1) { 2430 if (startPeriod >= life / 2 || startPeriod == life / 2) { 2431 part = startPeriod - life / 2; 2432 startPeriod = life / 2; 2433 endPeriod -= part; 2434 life1 += 1; 2435 } 2436 } 2437 } 2438 2439 cost -= vdbInterVDB(cost, salvage, life, life1, startPeriod, depreciationFactor); 2440 res = vdbInterVDB(cost, salvage, life, life - startPeriod, endPeriod - startPeriod, depreciationFactor); 2441 } // end not flag 2442 2443 return Value(res); 2444 } 2445 2446 2447 // 2448 // Function: XIRR 2449 // 2450 // Compute the internal rate of return for a non-periodic series of cash flows. 2451 // 2452 // XIRR ( Values; Dates; [ Guess = 0.1 ] ) 2453 // 2454 2455 // TODO sascha check dates 2456 Value func_xirr(valVector args, ValueCalc *calc, FuncExtra *) 2457 { 2458 double resultRate = 0.1; 2459 if (args.count() > 2) 2460 resultRate = calc->conv()->asFloat(args[2]).asFloat(); 2461 2462 // check pairs and count >= 2 and guess > -1.0 2463 if (args[0].count() != args[1].count() || args[1].count() < 2 || resultRate <= -1.0) 2464 return Value::errorVALUE(); 2465 2466 // define max epsilon 2467 static const double maxEpsilon = 1e-10; 2468 2469 // max number of iterations 2470 static const int maxIter = 50; 2471 2472 // Newton's method - try to find a res, with a accuracy of maxEpsilon 2473 double newRate, rateEpsilon, resultValue; 2474 int i = 0; 2475 bool contLoop; 2476 2477 do { 2478 resultValue = xirrResult(args, calc, resultRate); 2479 newRate = resultRate - resultValue / xirrResultDerive(args, calc, resultRate); 2480 rateEpsilon = fabs(newRate - resultRate); 2481 resultRate = newRate; 2482 contLoop = (rateEpsilon > maxEpsilon) && (fabs(resultValue) > maxEpsilon); 2483 } while (contLoop && (++i < maxIter)); 2484 2485 if (contLoop) 2486 return Value::errorVALUE(); 2487 2488 return Value(resultRate); 2489 } 2490 2491 // 2492 // Function: xnpv 2493 // 2494 // Compute the net present value of a series of cash flows. 2495 // 2496 // XNPV ( Rate; Values; Dates ) 2497 // 2498 Value func_xnpv(valVector args, ValueCalc *calc, FuncExtra *) 2499 { 2500 double rate = calc->conv()->asFloat(args[0]).asFloat(); 2501 ++rate; 2502 2503 int numValues = args[1].count(); 2504 int numDates = args[2].count(); 2505 2506 double res = 0; 2507 2508 // check pairs 2509 if (numValues != numDates || numValues < 2) 2510 return Value::errorVALUE(); 2511 // check rate 2512 if (rate < -1.0) 2513 return Value::errorNUM(); 2514 2515 QDate date0 = calc->conv()->asDate(args[2].element(0)).asDate(calc->settings()); 2516 double val; 2517 QDate date; 2518 2519 for (int i = 0; i < numValues; ++i) { 2520 val = calc->conv()->asFloat(args[1].element(i)).asFloat(); 2521 Value tmpDate(calc->conv()->asDate(args[2].element(i))); 2522 2523 if (tmpDate.isError()) return tmpDate; 2524 date = tmpDate.asDate(calc->settings()); 2525 2526 // check if date is valid 2527 if (!date.isValid()) 2528 return Value::errorNUM(); 2529 2530 int days = date0.daysTo(date); 2531 2532 res += val / pow(rate, days / 365.0); 2533 } 2534 2535 return Value(res); 2536 } 2537 2538 2539 // 2540 // YIELDDISC 2541 // 2542 Value func_yielddisc(valVector args, ValueCalc *calc, FuncExtra *) 2543 { 2544 QDate settlement = calc->conv()->asDate(args[0]).asDate(calc->settings()); 2545 QDate maturity = calc->conv()->asDate(args[1]).asDate(calc->settings()); 2546 double price = calc->conv()->asFloat(args[2]).asFloat(); 2547 double redemp = calc->conv()->asFloat(args[3]).asFloat(); 2548 2549 // opt. basis 2550 int basis = 0; 2551 if (args.count() > 4) 2552 basis = calc->conv()->asInteger(args[4]).asInteger(); 2553 2554 if (price <= 0.0 || redemp <= 0.0 || settlement >= maturity) 2555 return Value::errorVALUE(); 2556 2557 QDate date0 = calc->settings()->referenceDate(); // referenceDate 2558 2559 double res = (redemp / price) - 1.0; 2560 res /= yearFrac(date0, settlement, maturity, basis); 2561 2562 return Value(res); 2563 } 2564 2565 2566 // 2567 // YIELDMAT 2568 // 2569 Value func_yieldmat(valVector args, ValueCalc *calc, FuncExtra *) 2570 { 2571 QDate settlement = calc->conv()->asDate(args[0]).asDate(calc->settings()); 2572 QDate maturity = calc->conv()->asDate(args[1]).asDate(calc->settings()); 2573 QDate issue = calc->conv()->asDate(args[2]).asDate(calc->settings()); 2574 long double rate = calc->conv()->asFloat(args[3]).asFloat(); 2575 long double price = calc->conv()->asFloat(args[4]).asFloat(); 2576 2577 // opt. basis 2578 int basis = 0; 2579 if (args.count() > 5) 2580 basis = calc->conv()->asInteger(args[5]).asInteger(); 2581 2582 if (price <= 0.0 || rate <= 0.0 || settlement >= maturity) 2583 return Value::errorVALUE(); 2584 2585 QDate date0 = calc->settings()->referenceDate(); // referenceDate 2586 2587 long double issMat = yearFrac(date0, issue, maturity, basis); 2588 long double issSet = yearFrac(date0, issue, settlement, basis); 2589 long double setMat = yearFrac(date0, settlement, maturity, basis); 2590 2591 long double res = 1.0l + issMat * rate; 2592 res /= price / 100.0l + issSet * rate; 2593 res--; 2594 res /= setMat; 2595 2596 return Value(res); 2597 } 2598 2599 // 2600 // Function: zero_coupon 2601 // 2602 Value func_zero_coupon(valVector args, ValueCalc *calc, FuncExtra *) 2603 { 2604 // Returns effective interest rate given nominal rate and periods per year 2605 2606 Value face = args[0]; 2607 Value rate = args[1]; 2608 Value years = args[2]; 2609 2610 // face / pow(1 + rate, years) 2611 return calc->div(face, calc->pow(calc->add(rate, 1), years)); 2612 } 2613 2614 #include "financial.moc"