diff options
Diffstat (limited to 'scaddins/source')
-rw-r--r-- | scaddins/source/pricing/black_scholes.cxx | 960 | ||||
-rw-r--r-- | scaddins/source/pricing/black_scholes.hxx | 153 | ||||
-rw-r--r-- | scaddins/source/pricing/pricing.component | 26 | ||||
-rw-r--r-- | scaddins/source/pricing/pricing.cxx | 739 | ||||
-rw-r--r-- | scaddins/source/pricing/pricing.hrc | 54 | ||||
-rw-r--r-- | scaddins/source/pricing/pricing.hxx | 418 | ||||
-rw-r--r-- | scaddins/source/pricing/pricing.src | 436 |
7 files changed, 2786 insertions, 0 deletions
diff --git a/scaddins/source/pricing/black_scholes.cxx b/scaddins/source/pricing/black_scholes.cxx new file mode 100644 index 000000000000..f99906e03fdb --- /dev/null +++ b/scaddins/source/pricing/black_scholes.cxx @@ -0,0 +1,960 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright (C) 2012 Tino Kluge <tino.kluge@hrz.tu-chemnitz.de> + * + */ + +#include <cstdio> +#include <cstdlib> +#include <cmath> +#include <cassert> +#include <algorithm> +#include <rtl/math.hxx> +#include "black_scholes.hxx" + +// options prices and greeks in the Black-Scholes model +// also known as TV (theoretical value) +// +// the code is structured as follows: +// +// (1) basic assets +// - cash-or-nothing option: bincash() +// - asset-or-nothing option: binasset() +// +// (2) derived basic assets, can all be priced based on (1) +// - vanilla put/call: putcall() = +/- ( binasset() - K*bincash() ) +// - truncated put/call (barriers active at maturity only) +// +// (3) write a wrapper function to include all vanilla pricers +// - this is so we don't duplicate code when pricing barriers +// as this is derived from vanillas +// +// (4) single barrier options (knock-out), priced based on truncated vanillas +// - it follows from the reflection principle that the price W(S) of a +// single barrier option is given by +// W(S) = V(S) - (B/S)^a V(B^2/S), a = 2(rd-rf)/vol^2 - 1 +// where V(S) is the price of the corresponding truncated vanilla +// option +// - to reduce code duplication and in anticipation of double barrier +// options we write the following function +// barrier_term(S,c) = V(c*S) - (B/S)^a V(c*B^2/S) +// +// (5) double barrier options (knock-out) +// - value is an infinite sum over option prices of the corresponding +// truncated vanillas (truncated at both barriers): +// +// W(S)=sum (B2/B1)^(i*a) (V(S(B2/B1)^(2i)) - (B1/S)^a V(B1^2/S (B2/B1)^(2i)) +// +// (6) write routines for put/call barriers and touch options which +// mainly call the general double barrier pricer +// the main routines are touch() and barrier() +// both can price in/out barriers, double/single barriers as well as +// vanillas +// +// +// the framework allows any barriers to be priced as long as we define +// the value/greek functions for the corresponding truncated vanilla +// and wrap them into internal::vanilla() and internal::vanilla_trunc() +// +// disadvantage of that approach is that due to the rules of +// differentiations the formulas for greeks become long and possible +// simplifications in the formulas won't be made +// +// other code inefficiency due to multiplication with pm (+/- 1) +// cvtsi2sd: int-->double, 6/3 cycles +// mulsd: double-double multiplication, 5/1 cycles +// with -O3, however, it compiles 2 versions with pm=1, and pm=-1 +// which are efficient +// note this is tiny anyway as compared to exp/log (100 cycles), +// pow (200 cycles), erf (70 cycles) +// +// this code is not tested for numerical instability, ie overruns, +// underruns, accuracy, etc + + +namespace sca { +namespace pricing { + +namespace bs { + + +// helper functions +// ---------------- +inline double sqr(double x) { + return x*x; +} +// normal density (see also ScInterpreter::phi) +inline double dnorm(double x) { + //return (1.0/sqrt(2.0*M_PI))*exp(-0.5*x*x); // windows may not have M_PI + return 0.39894228040143268*exp(-0.5*x*x); +} +// cumulative normal distribution (see also ScInterpreter::integralPhi) +inline double pnorm(double x) { + //return 0.5*(erf(sqrt(0.5)*x)+1.0); // windows may not have erf + return 0.5 * ::rtl::math::erfc(-x * 0.7071067811865475); +} + + + +// binary option cash (domestic) +// call - pays 1 if S_T is above strike K +// put - pays 1 if S_T is below strike K +double bincash(double S, double vol, double rd, double rf, + double tau, double K, + types::PutCall pc, types::Greeks greeks) { + assert(tau>=0.0); + assert(S>0.0); + assert(vol>0.0); + assert(K>=0.0); + + double val=0.0; + + if(tau<=0.0) { + // special case tau=0 (expiry) + switch(greeks) { + case types::Value: + if( (pc==types::Call && S>=K) || (pc==types::Put && S<=K) ) { + val = 1.0; + } else { + val = 0.0; + } + break; + default: + val = 0.0; + } + } else if(K==0.0) { + // special case with zero strike + if(pc==types::Put) { + // up-and-out (put) with K=0 + val=0.0; + } else { + // down-and-out (call) with K=0 (zero coupon bond) + switch(greeks) { + case types::Value: + val = 1.0; + break; + case types::Theta: + val = rd; + break; + case types::Rho_d: + val = -tau; + break; + default: + val = 0.0; + } + } + } else { + // standard case with K>0, tau>0 + double d1 = ( log(S/K)+(rd-rf+0.5*vol*vol)*tau ) / (vol*sqrt(tau)); + double d2 = d1 - vol*sqrt(tau); + int pm = (pc==types::Call) ? 1 : -1; + + switch(greeks) { + case types::Value: + val = pnorm(pm*d2); + break; + case types::Delta: + val = pm*dnorm(d2)/(S*vol*sqrt(tau)); + break; + case types::Gamma: + val = -pm*dnorm(d2)*d1/(sqr(S*vol)*tau); + break; + case types::Theta: + val = rd*pnorm(pm*d2) + + pm*dnorm(d2)*(log(S/K)/(vol*sqrt(tau))-0.5*d2)/tau; + break; + case types::Vega: + val = -pm*dnorm(d2)*d1/vol; + break; + case types::Volga: + val = pm*dnorm(d2)/(vol*vol)*(-d1*d1*d2+d1+d2); + break; + case types::Vanna: + val = pm*dnorm(d2)/(S*vol*vol*sqrt(tau))*(d1*d2-1.0); + break; + case types::Rho_d: + val = -tau*pnorm(pm*d2) + pm*dnorm(d2)*sqrt(tau)/vol; + break; + case types::Rho_f: + val = -pm*dnorm(d2)*sqrt(tau)/vol; + break; + default: + printf("bincash: greek %ui not implemented\n", greeks ); + abort(); + } + } + return exp(-rd*tau)*val; +} + + + +// binary option asset (foreign) +// call - pays S_T if S_T is above strike K +// put - pays S_T if S_T is below strike K +double binasset(double S, double vol, double rd, double rf, + double tau, double K, + types::PutCall pc, types::Greeks greeks) { + assert(tau>=0.0); + assert(S>0.0); + assert(vol>0.0); + assert(K>=0.0); + + double val=0.0; + if(tau<=0.0) { + // special case tau=0 (expiry) + switch(greeks) { + case types::Value: + if( (pc==types::Call && S>=K) || (pc==types::Put && S<=K) ) { + val = S; + } else { + val = 0.0; + } + break; + case types::Delta: + if( (pc==types::Call && S>=K) || (pc==types::Put && S<=K) ) { + val = 1.0; + } else { + val = 0.0; + } + break; + default: + val = 0.0; + } + } else if(K==0.0) { + // special case with zero strike (forward with zero strike) + if(pc==types::Put) { + // up-and-out (put) with K=0 + val = 0.0; + } else { + // down-and-out (call) with K=0 (type of forward) + switch(greeks) { + case types::Value: + val = S; + break; + case types::Delta: + val = 1.0; + break; + case types::Theta: + val = rf*S; + break; + case types::Rho_f: + val = -tau*S; + break; + default: + val = 0.0; + } + } + } else { + // normal case + double d1 = ( log(S/K)+(rd-rf+0.5*vol*vol)*tau ) / (vol*sqrt(tau)); + double d2 = d1 - vol*sqrt(tau); + int pm = (pc==types::Call) ? 1 : -1; + + switch(greeks) { + case types::Value: + val = S*pnorm(pm*d1); + break; + case types::Delta: + val = pnorm(pm*d1) + pm*dnorm(d1)/(vol*sqrt(tau)); + break; + case types::Gamma: + val = -pm*dnorm(d1)*d2/(S*sqr(vol)*tau); + break; + case types::Theta: + val = rf*S*pnorm(pm*d1) + + pm*S*dnorm(d1)*(log(S/K)/(vol*sqrt(tau))-0.5*d1)/tau; + break; + case types::Vega: + val = -pm*S*dnorm(d1)*d2/vol; + break; + case types::Volga: + val = pm*S*dnorm(d1)/(vol*vol)*(-d1*d2*d2+d1+d2); + break; + case types::Vanna: + val = pm*dnorm(d1)/(vol*vol*sqrt(tau))*(d2*d2-1.0); + break; + case types::Rho_d: + val = pm*S*dnorm(d1)*sqrt(tau)/vol; + break; + case types::Rho_f: + val = -tau*S*pnorm(pm*d1) - pm*S*dnorm(d1)*sqrt(tau)/vol; + break; + default: + printf("binasset: greek %ui not implemented\n", greeks ); + abort(); + } + } + return exp(-rf*tau)*val; +} + +// just for convenience we can combine bincash and binasset into +// one function binary +// using bincash() if fd==types::Domestic +// using binasset() if fd==types::Foreign +double binary(double S, double vol, double rd, double rf, + double tau, double K, + types::PutCall pc, types::ForDom fd, + types::Greeks greek) { + double val=0.0; + switch(fd) { + case types::Domestic: + val = bincash(S,vol,rd,rf,tau,K,pc,greek); + break; + case types::Foreign: + val = binasset(S,vol,rd,rf,tau,K,pc,greek); + break; + default: + // never get here + assert(false); + } + return val; +} + +// further wrapper to combine single/double barrier binary options +// into one function +// B1<=0 - it is assumed lower barrier not set +// B2<=0 - it is assumed upper barrier not set +double binary(double S, double vol, double rd, double rf, + double tau, double B1, double B2, + types::ForDom fd, types::Greeks greek) { + assert(tau>=0.0); + assert(S>0.0); + assert(vol>0.0); + + double val=0.0; + + if(B1<=0.0 && B2<=0.0) { + // no barriers set, payoff 1.0 (domestic) or S_T (foreign) + val = binary(S,vol,rd,rf,tau,0.0,types::Call,fd,greek); + } else if(B1<=0.0 && B2>0.0) { + // upper barrier (put) + val = binary(S,vol,rd,rf,tau,B2,types::Put,fd,greek); + } else if(B1>0.0 && B2<=0.0) { + // lower barrier (call) + val = binary(S,vol,rd,rf,tau,B1,types::Call,fd,greek); + } else if(B1>0.0 && B2>0.0) { + // double barrier + if(B2<=B1) { + val = 0.0; + } else { + val = binary(S,vol,rd,rf,tau,B2,types::Put,fd,greek) + - binary(S,vol,rd,rf,tau,B1,types::Put,fd,greek); + } + } else { + // never get here + assert(false); + } + + return val; +} + + + +// vanilla put/call option +// call pays (S_T-K)^+ +// put pays (K-S_T)^+ +// this is the same as: +/- (binasset - K*bincash) +double putcall(double S, double vol, double rd, double rf, + double tau, double K, + types::PutCall putcall, types::Greeks greeks) { + + assert(tau>=0.0); + assert(S>0.0); + assert(vol>0.0); + assert(K>=0.0); + + double val = 0.0; + int pm = (putcall==types::Call) ? 1 : -1; + + if(K==0 || tau==0.0) { + // special cases, simply refer to binasset() and bincash() + val = pm * ( binasset(S,vol,rd,rf,tau,K,putcall,greeks) + - K*bincash(S,vol,rd,rf,tau,K,putcall,greeks) ); + } else { + // general case + // we could just use pm*(binasset-K*bincash), however + // since the formula for delta and gamma simplify we write them + // down here + double d1 = ( log(S/K)+(rd-rf+0.5*vol*vol)*tau ) / (vol*sqrt(tau)); + double d2 = d1 - vol*sqrt(tau); + + switch(greeks) { + case types::Value: + val = pm * ( exp(-rf*tau)*S*pnorm(pm*d1)-exp(-rd*tau)*K*pnorm(pm*d2) ); + break; + case types::Delta: + val = pm*exp(-rf*tau)*pnorm(pm*d1); + break; + case types::Gamma: + val = exp(-rf*tau)*dnorm(d1)/(S*vol*sqrt(tau)); + break; + default: + // too lazy for the other greeks, so simply refer to binasset/bincash + val = pm * ( binasset(S,vol,rd,rf,tau,K,putcall,greeks) + - K*bincash(S,vol,rd,rf,tau,K,putcall,greeks) ); + } + } + return val; +} + +// truncated put/call option, single barrier +// need to specify whether it's down-and-out or up-and-out +// regular (keeps monotonicity): down-and-out for call, up-and-out for put +// reverse (destroys monoton): up-and-out for call, down-and-out for put +// call pays (S_T-K)^+ +// put pays (K-S_T)^+ +double putcalltrunc(double S, double vol, double rd, double rf, + double tau, double K, double B, + types::PutCall pc, types::KOType kotype, + types::Greeks greeks) { + + assert(tau>=0.0); + assert(S>0.0); + assert(vol>0.0); + assert(K>=0.0); + assert(B>=0.0); + + int pm = (pc==types::Call) ? 1 : -1; + double val = 0.0; + + switch(kotype) { + case types::Regular: + if( (pc==types::Call && B<=K) || (pc==types::Put && B>=K) ) { + // option degenerates to standard plain vanilla call/put + val = putcall(S,vol,rd,rf,tau,K,pc,greeks); + } else { + // normal case with truncation + val = pm * ( binasset(S,vol,rd,rf,tau,B,pc,greeks) + - K*bincash(S,vol,rd,rf,tau,B,pc,greeks) ); + } + break; + case types::Reverse: + if( (pc==types::Call && B<=K) || (pc==types::Put && B>=K) ) { + // option degenerates to zero payoff + val = 0.0; + } else { + // normal case with truncation + val = binasset(S,vol,rd,rf,tau,K,types::Call,greeks) + - binasset(S,vol,rd,rf,tau,B,types::Call,greeks) + - K * ( bincash(S,vol,rd,rf,tau,K,types::Call,greeks) + - bincash(S,vol,rd,rf,tau,B,types::Call,greeks) ); + } + break; + default: + assert(false); + } + return val; +} + +// wrapper function for put/call option which combines +// double/single/no truncation barrier +// B1<=0 - assume no lower barrier +// B2<=0 - assume no upper barrier +double putcalltrunc(double S, double vol, double rd, double rf, + double tau, double K, double B1, double B2, + types::PutCall pc, types::Greeks greek) { + + assert(tau>=0.0); + assert(S>0.0); + assert(vol>0.0); + assert(K>=0.0); + + double val=0.0; + + if(B1<=0.0 && B2<=0.0) { + // no barriers set, plain vanilla + val = putcall(S,vol,rd,rf,tau,K,pc,greek); + } else if(B1<=0.0 && B2>0.0) { + // upper barrier: reverse barrier for call, regular barrier for put + if(pc==types::Call) { + val = putcalltrunc(S,vol,rd,rf,tau,K,B2,pc,types::Reverse,greek); + } else { + val = putcalltrunc(S,vol,rd,rf,tau,K,B2,pc,types::Regular,greek); + } + } else if(B1>0.0 && B2<=0.0) { + // lower barrier: regular barrier for call, reverse barrier for put + if(pc==types::Call) { + val = putcalltrunc(S,vol,rd,rf,tau,K,B1,pc,types::Regular,greek); + } else { + val = putcalltrunc(S,vol,rd,rf,tau,K,B1,pc,types::Reverse,greek); + } + } else if(B1>0.0 && B2>0.0) { + // double barrier + if(B2<=B1) { + val = 0.0; + } else { + int pm = (pc==types::Call) ? 1 : -1; + val = pm * ( + putcalltrunc(S,vol,rd,rf,tau,K,B1,pc,types::Regular,greek) + - putcalltrunc(S,vol,rd,rf,tau,K,B2,pc,types::Regular,greek) + ); + } + } else { + // never get here + assert(false); + } + return val; +} + +namespace internal { + +// wrapper function for all non-path dependent options +// this is only an internal function, used to avoid code duplication when +// going to path-dependent barrier options, +// K<0 - assume binary option +// K>=0 - assume put/call option +double vanilla(double S, double vol, double rd, double rf, + double tau, double K, double B1, double B2, + types::PutCall pc, types::ForDom fd, + types::Greeks greek) { + double val = 0.0; + if(K<0.0) { + // binary option if K<0 + val = binary(S,vol,rd,rf,tau,B1,B2,fd,greek); + } else { + val = putcall(S,vol,rd,rf,tau,K,pc,greek); + } + return val; +} +double vanilla_trunc(double S, double vol, double rd, double rf, + double tau, double K, double B1, double B2, + types::PutCall pc, types::ForDom fd, + types::Greeks greek) { + double val = 0.0; + if(K<0.0) { + // binary option if K<0 + // truncated is actually the same as the vanilla binary + val = binary(S,vol,rd,rf,tau,B1,B2,fd,greek); + } else { + val = putcalltrunc(S,vol,rd,rf,tau,K,B1,B2,pc,greek); + } + return val; +} + +} // namespace internal + + +// --------------------------------------------------------------------- +// path dependent options +// --------------------------------------------------------------------- + +namespace internal { + +// helper term for any type of options with continuously monitored barriers, +// internal, should not be called from outside +// calculates value and greeks based on +// V(S) = V1(sc*S) - (B/S)^a V1(sc*B^2/S) +// (a=2 mu/vol^2, mu drift in logspace, ie. mu=(rd-rf-1/2vol^2)) +// with sc=1 and V1() being the price of the respective truncated +// vanilla option, V() would be the price of the respective barrier +// option if only one barrier is present +double barrier_term(double S, double vol, double rd, double rf, + double tau, double K, double B1, double B2, double sc, + types::PutCall pc, types::ForDom fd, + types::Greeks greek) { + + assert(tau>=0.0); + assert(S>0.0); + assert(vol>0.0); + + // V(S) = V1(sc*S) - (B/S)^a V1(sc*B^2/S) + double val = 0.0; + double B = (B1>0.0) ? B1 : B2; + double a = 2.0*(rd-rf)/(vol*vol)-1.0; // helper variable + double b = 4.0*(rd-rf)/(vol*vol*vol); // helper variable -da/dvol + double c = 12.0*(rd-rf)/(vol*vol*vol*vol); // helper -db/dvol + switch(greek) { + case types::Value: + val = vanilla_trunc(sc*S,vol,rd,rf,tau,K,B1,B2,pc,fd,greek) + - pow(B/S,a)* + vanilla_trunc(sc*B*B/S,vol,rd,rf,tau,K,B1,B2,pc,fd,greek); + break; + case types::Delta: + val = sc*vanilla_trunc(sc*S,vol,rd,rf,tau,K,B1,B2,pc,fd,greek) + + pow(B/S,a) * ( + a/S* + vanilla_trunc(sc*B*B/S,vol,rd,rf,tau,K,B1,B2,pc,fd,types::Value) + + sqr(B/S)*sc* + vanilla_trunc(sc*B*B/S,vol,rd,rf,tau,K,B1,B2,pc,fd,greek) + ); + break; + case types::Gamma: + val = sc*sc*vanilla_trunc(sc*S,vol,rd,rf,tau,K,B1,B2,pc,fd,greek) + - pow(B/S,a) * ( + a*(a+1.0)/(S*S)* + vanilla_trunc(sc*B*B/S,vol,rd,rf,tau,K,B1,B2,pc,fd,types::Value) + + (2.0*a+2.0)*B*B/(S*S*S)*sc* + vanilla_trunc(sc*B*B/S,vol,rd,rf,tau,K,B1,B2,pc,fd,types::Delta) + + sqr(sqr(B/S))*sc*sc* + vanilla_trunc(sc*B*B/S,vol,rd,rf,tau,K,B1,B2,pc,fd,types::Gamma) + ); + break; + case types::Theta: + val = vanilla_trunc(sc*S,vol,rd,rf,tau,K,B1,B2,pc,fd,greek) + - pow(B/S,a)* + vanilla_trunc(sc*B*B/S,vol,rd,rf,tau,K,B1,B2,pc,fd,greek); + break; + case types::Vega: + val = vanilla_trunc(sc*S,vol,rd,rf,tau,K,B1,B2,pc,fd,greek) + - pow(B/S,a) * ( + - b*log(B/S)* + vanilla_trunc(sc*B*B/S,vol,rd,rf,tau,K,B1,B2,pc,fd,types::Value) + + 1.0* + vanilla_trunc(sc*B*B/S,vol,rd,rf,tau,K,B1,B2,pc,fd,greek) + ); + break; + case types::Volga: + val = vanilla_trunc(sc*S,vol,rd,rf,tau,K,B1,B2,pc,fd,greek) + - pow(B/S,a) * ( + log(B/S)*(b*b*log(B/S)+c)* + vanilla_trunc(sc*B*B/S,vol,rd,rf,tau,K,B1,B2,pc,fd,types::Value) + - 2.0*b*log(B/S)* + vanilla_trunc(sc*B*B/S,vol,rd,rf,tau,K,B1,B2,pc,fd,types::Vega) + + 1.0* + vanilla_trunc(sc*B*B/S,vol,rd,rf,tau,K,B1,B2,pc,fd,types::Volga) + ); + break; + case types::Vanna: + val = sc*vanilla_trunc(sc*S,vol,rd,rf,tau,K,B1,B2,pc,fd,greek) + - pow(B/S,a) * ( + b/S*(log(B/S)*a+1.0)* + vanilla_trunc(B*B/S*sc,vol,rd,rf,tau,K,B1,B2,pc,fd,types::Value) + + b*log(B/S)*sqr(B/S)*sc* + vanilla_trunc(B*B/S*sc,vol,rd,rf,tau,K,B1,B2,pc,fd,types::Delta) + - a/S* + vanilla_trunc(B*B/S*sc,vol,rd,rf,tau,K,B1,B2,pc,fd,types::Vega) + - sqr(B/S)*sc* + vanilla_trunc(B*B/S*sc,vol,rd,rf,tau,K,B1,B2,pc,fd,types::Vanna) + ); + break; + case types::Rho_d: + val = vanilla_trunc(sc*S,vol,rd,rf,tau,K,B1,B2,pc,fd,greek) + - pow(B/S,a) * ( + 2.0*log(B/S)/(vol*vol)* + vanilla_trunc(sc*B*B/S,vol,rd,rf,tau,K,B1,B2,pc,fd,types::Value) + + 1.0* + vanilla_trunc(sc*B*B/S,vol,rd,rf,tau,K,B1,B2,pc,fd,greek) + ); + break; + case types::Rho_f: + val = vanilla_trunc(sc*S,vol,rd,rf,tau,K,B1,B2,pc,fd,greek) + - pow(B/S,a) * ( + - 2.0*log(B/S)/(vol*vol)* + vanilla_trunc(sc*B*B/S,vol,rd,rf,tau,K,B1,B2,pc,fd,types::Value) + + 1.0* + vanilla_trunc(sc*B*B/S,vol,rd,rf,tau,K,B1,B2,pc,fd,greek) + ); + break; + default: + printf("barrier_term: greek %ui not implemented\n", greek ); + abort(); + } + return val; +} + +// one term of the infinite sum for the valuation of double barriers +double barrier_double_term( double S, double vol, double rd, double rf, + double tau, double K, double B1, double B2, + double fac, double sc, int i, + types::PutCall pc, types::ForDom fd, types::Greeks greek) { + + double val = 0.0; + double b = 4.0*i*(rd-rf)/(vol*vol*vol); // helper variable -da/dvol + double c = 12.0*i*(rd-rf)/(vol*vol*vol*vol); // helper -db/dvol + switch(greek) { + case types::Value: + val = fac*barrier_term(S,vol,rd,rf,tau,K,B1,B2,sc,pc,fd,greek); + break; + case types::Delta: + val = fac*barrier_term(S,vol,rd,rf,tau,K,B1,B2,sc,pc,fd,greek); + break; + case types::Gamma: + val = fac*barrier_term(S,vol,rd,rf,tau,K,B1,B2,sc,pc,fd,greek); + break; + case types::Theta: + val = fac*barrier_term(S,vol,rd,rf,tau,K,B1,B2,sc,pc,fd,greek); + break; + case types::Vega: + val = fac*barrier_term(S,vol,rd,rf,tau,K,B1,B2,sc,pc,fd,greek) + - b*log(B2/B1)*fac * + barrier_term(S,vol,rd,rf,tau,K,B1,B2,sc,pc,fd,types::Value); + break; + case types::Volga: + val = fac*barrier_term(S,vol,rd,rf,tau,K,B1,B2,sc,pc,fd,greek) + - 2.0*b*log(B2/B1)*fac * + barrier_term(S,vol,rd,rf,tau,K,B1,B2,sc,pc,fd,types::Vega) + + log(B2/B1)*fac*(c+b*b*log(B2/B1)) * + barrier_term(S,vol,rd,rf,tau,K,B1,B2,sc,pc,fd,types::Value); + break; + case types::Vanna: + val = fac*barrier_term(S,vol,rd,rf,tau,K,B1,B2,sc,pc,fd,greek) + - b*log(B2/B1)*fac * + barrier_term(S,vol,rd,rf,tau,K,B1,B2,sc,pc,fd,types::Delta); + break; + case types::Rho_d: + val = fac*barrier_term(S,vol,rd,rf,tau,K,B1,B2,sc,pc,fd,greek) + + 2.0*i/(vol*vol)*log(B2/B1)*fac * + barrier_term(S,vol,rd,rf,tau,K,B1,B2,sc,pc,fd,types::Value); + break; + case types::Rho_f: + val = fac*barrier_term(S,vol,rd,rf,tau,K,B1,B2,sc,pc,fd,greek) + - 2.0*i/(vol*vol)*log(B2/B1)*fac * + barrier_term(S,vol,rd,rf,tau,K,B1,B2,sc,pc,fd,types::Value); + break; + default: + printf("barrier_double_term: greek %ui not implemented\n", greek ); + abort(); + } + return val; +} + +// general pricer for any type of options with continuously monitored barriers +// allows two, one or zero barriers, only knock-out style +// payoff profiles allowed based on vanilla_trunc() +double barrier_ko(double S, double vol, double rd, double rf, + double tau, double K, double B1, double B2, + types::PutCall pc, types::ForDom fd, + types::Greeks greek) { + + assert(tau>=0.0); + assert(S>0.0); + assert(vol>0.0); + + double val = 0.0; + + if(B1<=0.0 && B2<=0.0) { + // no barriers --> vanilla case + val = vanilla(S,vol,rd,rf,tau,K,B1,B2,pc,fd,greek); + } else if(B1>0.0 && B2<=0.0) { + // lower barrier + if(S<=B1) { + val = 0.0; // knocked out + } else { + val = barrier_term(S,vol,rd,rf,tau,K,B1,B2,1.0,pc,fd,greek); + } + } else if(B1<=0.0 && B2>0.0) { + // upper barrier + if(S>=B2) { + val = 0.0; // knocked out + } else { + val = barrier_term(S,vol,rd,rf,tau,K,B1,B2,1.0,pc,fd,greek); + } + } else if(B1>0.0 && B2>0.0) { + // double barrier + if(S<=B1 || S>=B2) { + val = 0.0; // knocked out (always true if wrong input B1>B2) + } else { + // more complex calculation as we have to evaluate an infinite + // sum + // to reduce very costly pow() calls we define some variables + double a = 2.0*(rd-rf)/(vol*vol)-1.0; // 2 (mu-1/2vol^2)/sigma^2 + double BB2=sqr(B2/B1); + double BBa=pow(B2/B1,a); + double BB2inv=1.0/BB2; + double BBainv=1.0/BBa; + double fac=1.0; + double facinv=1.0; + double sc=1.0; + double scinv=1.0; + + // initial term i=0 + val=barrier_double_term(S,vol,rd,rf,tau,K,B1,B2,fac,sc,0,pc,fd,greek); + // infinite loop, 10 should be plenty, normal would be 2 + for(int i=1; i<10; i++) { + fac*=BBa; + facinv*=BBainv; + sc*=BB2; + scinv*=BB2inv; + double add = + barrier_double_term(S,vol,rd,rf,tau,K,B1,B2,fac,sc,i,pc,fd,greek) + + barrier_double_term(S,vol,rd,rf,tau,K,B1,B2,facinv,scinv,-i,pc,fd,greek); + val += add; + //printf("%i: val=%e (add=%e)\n",i,val,add); + if(fabs(add) <= 1e-12*fabs(val)) { + break; + } + } + // not knocked-out double barrier end + } + // double barrier end + } else { + // no such barrier combination exists + assert(false); + } + + return val; +} + +// knock-in style barrier +double barrier_ki(double S, double vol, double rd, double rf, + double tau, double K, double B1, double B2, + types::PutCall pc, types::ForDom fd, + types::Greeks greek) { + return vanilla(S,vol,rd,rf,tau,K,B1,B2,pc,fd,greek) + -barrier_ko(S,vol,rd,rf,tau,K,B1,B2,pc,fd,greek); +} + +// general barrier +double barrier(double S, double vol, double rd, double rf, + double tau, double K, double B1, double B2, + types::PutCall pc, types::ForDom fd, + types::BarrierKIO kio, types::BarrierActive bcont, + types::Greeks greek) { + + double val = 0.0; + if( kio==types::KnockOut && bcont==types::Maturity ) { + // truncated vanilla option + val = vanilla_trunc(S,vol,rd,rf,tau,K,B1,B2,pc,fd,greek); + } else if ( kio==types::KnockOut && bcont==types::Continuous ) { + // standard knock-out barrier + val = barrier_ko(S,vol,rd,rf,tau,K,B1,B2,pc,fd,greek); + } else if ( kio==types::KnockIn && bcont==types::Maturity ) { + // inverse truncated vanilla + val = vanilla(S,vol,rd,rf,tau,K,B1,B2,pc,fd,greek) + - vanilla_trunc(S,vol,rd,rf,tau,K,B1,B2,pc,fd,greek); + } else if ( kio==types::KnockIn && bcont==types::Continuous ) { + // standard knock-in barrier + val = barrier_ki(S,vol,rd,rf,tau,K,B1,B2,pc,fd,greek); + } else { + // never get here + assert(false); + } + return val; +} + +} // namespace internal + + + + +// touch/no-touch options (cash/asset or nothing payoff profile) +double touch(double S, double vol, double rd, double rf, + double tau, double B1, double B2, types::ForDom fd, + types::BarrierKIO kio, types::BarrierActive bcont, + types::Greeks greek) { + + double K=-1.0; // dummy + types::PutCall pc = types::Call; // dummy + double val = 0.0; + if( kio==types::KnockOut && bcont==types::Maturity ) { + // truncated vanilla option + val = internal::vanilla_trunc(S,vol,rd,rf,tau,K,B1,B2,pc,fd,greek); + } else if ( kio==types::KnockOut && bcont==types::Continuous ) { + // standard knock-out barrier + val = internal::barrier_ko(S,vol,rd,rf,tau,K,B1,B2,pc,fd,greek); + } else if ( kio==types::KnockIn && bcont==types::Maturity ) { + // inverse truncated vanilla + val = internal::vanilla(S,vol,rd,rf,tau,K,-1.0,-1.0,pc,fd,greek) + - internal::vanilla_trunc(S,vol,rd,rf,tau,K,B1,B2,pc,fd,greek); + } else if ( kio==types::KnockIn && bcont==types::Continuous ) { + // standard knock-in barrier + val = internal::vanilla(S,vol,rd,rf,tau,K,-1.0,-1.0,pc,fd,greek) + - internal::barrier_ko(S,vol,rd,rf,tau,K,B1,B2,pc,fd,greek); + } else { + // never get here + assert(false); + } + return val; +} + +// barrier option (put/call payoff profile) +double barrier(double S, double vol, double rd, double rf, + double tau, double K, double B1, double B2, + double rebate, + types::PutCall pc, types::BarrierKIO kio, + types::BarrierActive bcont, + types::Greeks greek) { + assert(tau>=0.0); + assert(S>0.0); + assert(vol>0.0); + assert(K>=0.0); + types::ForDom fd = types::Domestic; + double val=internal::barrier(S,vol,rd,rf,tau,K,B1,B2,pc,fd,kio,bcont,greek); + if(rebate!=0.0) { + // opposite of barrier knock-in/out type + types::BarrierKIO kio2 = (kio==types::KnockIn) ? types::KnockOut + : types::KnockIn; + val += rebate*touch(S,vol,rd,rf,tau,B1,B2,fd,kio2,bcont,greek); + } + return val; +} + + + +// probability of hitting a barrier +// this is almost the same as the price of a touch option (domestic) +// as it pays one if a barrier is hit; we only have to offset the +// discounting and we get the probability +double prob_hit(double S, double vol, double mu, + double tau, double B1, double B2) { + double rd=0.0; + double rf=-mu; + return 1.0 - touch(S,vol,rd,rf,tau,B1,B2,types::Domestic,types::KnockOut, + types::Continuous, types::Value); +} + +// probability of being in-the-money, ie payoff is greater zero, +// assuming payoff(S_T) > 0 iff S_T in [B1, B2] +// this the same as the price of a cash or nothing option +// with no discounting +double prob_in_money(double S, double vol, double mu, + double tau, double B1, double B2) { + assert(S>0.0); + assert(vol>0.0); + assert(tau>=0.0); + double val = 0.0; + if( B1<B2 || B1<=0.0 || B2<=0.0 ) { + val = binary(S,vol,0.0,-mu,tau,B1,B2,types::Domestic,types::Value); + } + return val; +} +double prob_in_money(double S, double vol, double mu, + double tau, double K, double B1, double B2, + types::PutCall pc) { + assert(S>0.0); + assert(vol>0.0); + assert(tau>=0.0); + + // if K<0 we assume a binary option is given + if(K<0.0) { + return prob_in_money(S,vol,mu,tau,B1,B2); + } + + double val = 0.0; + double BM1, BM2; // range of in the money [BM1, BM2] + // non-sense parameters with no positive payoff + if( (B1>B2 && B1>0.0 && B2>0.0) || + (K>=B2 && B2>0.0 && pc==types::Call) || + (K<=B1 && pc==types::Put) ) { + val = 0.0; + // need to figure out between what barriers payoff is greater 0 + } else if(pc==types::Call) { + BM1=std::max(B1, K); + BM2=B2; + val = prob_in_money(S,vol,mu,tau,BM1,BM2); + } else if (pc==types::Put) { + BM1=B1; + BM2= (B2>0.0) ? std::min(B2,K) : K; + val = prob_in_money(S,vol,mu,tau,BM1,BM2); + } else { + // don't get here + assert(false); + } + return val; +} + + + +} // namespace bs + +} // namespace pricing +} // namespace sca + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/scaddins/source/pricing/black_scholes.hxx b/scaddins/source/pricing/black_scholes.hxx new file mode 100644 index 000000000000..5e665c535471 --- /dev/null +++ b/scaddins/source/pricing/black_scholes.hxx @@ -0,0 +1,153 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright (C) 2012 Tino Kluge <tino.kluge@hrz.tu-chemnitz.de> + * + */ + + +#ifndef BLACK_SCHOLES_HXX +#define BLACK_SCHOLES_HXX + +// options prices and greeks in the Black-Scholes model +// also known as TV (theoretical value) + +namespace sca { +namespace pricing { + +namespace bs { + +namespace types { +enum Greeks { + Value = 0, // + Delta = 1, // d/dS + Gamma = 2, // d^2/dS^2 + Theta = 3, // d/dt + Vega = 4, // d/dsigma + Volga = 5, // d^2/dsigma^2 + Vanna = 6, // d^2/dsigma dS + Rho_d = 7, // d/dr_d + Rho_f = 8 // d/dr_f +}; + +enum PutCall { + Call = 1, + Put = -1 +}; + +enum KOType { + Regular = 0, + Reverse = 1 +}; + +enum BarrierKIO { + KnockIn = -1, + KnockOut = 1 +}; + +// barrier observed continuously or just at maturity (truncated payoff) +enum BarrierActive { + Continuous = 0, + Maturity = 1 +}; + +enum ForDom { + Domestic = 0, + Foreign = 1 +}; + +} // namespace types + + +// binary option cash (domestic) +// call - pays 1 if S_T is above strike K +// put - pays 1 if S_T is below strike K +double bincash(double S, double vol, double rd, double rf, + double tau, double K, + types::PutCall pc, types::Greeks greeks); + +// binary option asset (foreign) +// call - pays S_T if S_T is above strike K +// put - pays S_T if S_T is below strike K +double binasset(double S, double vol, double rd, double rf, + double tau, double K, + types::PutCall pc, types::Greeks greeks); + + + +// vanilla put/call option +// call pays (S_T-K)^+ +// put pays (K-S_T)^+ +// this is the same as: +/- (binasset - K*bincash) +double putcall(double S, double vol, double rd, double rf, + double tau, double K, + types::PutCall putcall, types::Greeks greeks); + + +// truncated put/call option, single barrier +// need to specify whether it's down-and-out or up-and-out +// regular (keeps monotonicity): down-and-out for call, up-and-out for put +// reverse (destroys monoton): up-and-out for call, down-and-out for put +// call pays (S_T-K)^+ +// put pays (K-S_T)^+ +double putcalltrunc(double S, double vol, double rd, double rf, + double tau, double K, double B, + types::PutCall pc, types::KOType kotype, + types::Greeks greeks); + + +// wrapper function for put/call option which combines +// double/single/no truncation barrier +// B1<=0 - assume no lower barrier +// B2<=0 - assume no upper barrier +double putcalltrunc(double S, double vol, double rd, double rf, + double tau, double K, double B1, double B2, + types::PutCall pc, types::Greeks greek); + + + +// barrier +// touch/no-touch options (cash/asset or nothing payoff profile) +double touch(double S, double vol, double rd, double rf, + double tau, double B1, double B2, types::ForDom fd, + types::BarrierKIO kio, types::BarrierActive bcont, + types::Greeks greek); + +// barrier +// barrier option (put/call payoff profile) +double barrier(double S, double vol, double rd, double rf, + double tau, double K, double B1, double B2, + double rebate, + types::PutCall pc, types::BarrierKIO kio, + types::BarrierActive bcont, + types::Greeks greek); + + +// probability of hitting a barrier +double prob_hit(double S, double vol, double mu, + double tau, double B1, double B2); + + +// probability of being in-the-money, ie payoff is greater zero, +// assuming payoff(S_T) > 0 iff S_T in [B1, B2] +double prob_in_money(double S, double vol, double mu, + double tau, double B1, double B2); +double prob_in_money(double S, double vol, double mu, + double tau, double K, double B1, double B2, + types::PutCall pc); + + +} // namespace bs + +} // namespace pricing +} // namespace sca + + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/scaddins/source/pricing/pricing.component b/scaddins/source/pricing/pricing.component new file mode 100644 index 000000000000..d50ee37d7117 --- /dev/null +++ b/scaddins/source/pricing/pricing.component @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + --> + +<component loader="com.sun.star.loader.SharedLibrary" prefix="pricing" + xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="com.sun.star.sheet.addin.PricingFunctionsImpl"> + <service name="com.sun.star.sheet.AddIn"/> + <service name="com.sun.star.sheet.addin.PricingFunctions"/> + </implementation> +</component> diff --git a/scaddins/source/pricing/pricing.cxx b/scaddins/source/pricing/pricing.cxx new file mode 100644 index 000000000000..ba4cb31a9e4d --- /dev/null +++ b/scaddins/source/pricing/pricing.cxx @@ -0,0 +1,739 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +//------------------------------------------------------------------ +// +// pricing functions add in +// +// all of the UNO add-in technical details have been copied from +// ../datefunc/datefunc.cxx +// +//------------------------------------------------------------------ + +#include "pricing.hxx" +#include "black_scholes.hxx" +#include "pricing.hrc" +#include <cppuhelper/factory.hxx> +#include <osl/diagnose.h> +#include <rtl/ustrbuf.hxx> +#include <rtl/math.hxx> +#include <tools/resmgr.hxx> +#include <tools/rcid.h> + +#include <iostream> + +using namespace ::com::sun::star; +using namespace sca::pricing; + + +//------------------------------------------------------------------ + +#define ADDIN_SERVICE "com.sun.star.sheet.AddIn" +#define MY_SERVICE "com.sun.star.sheet.addin.PricingFunctions" +#define MY_IMPLNAME "com.sun.star.sheet.addin.PricingFunctionsImpl" + +//------------------------------------------------------------------ + +#define STR_FROM_ANSI( s ) OUString( s, strlen( s ), RTL_TEXTENCODING_MS_1252 ) + +//------------------------------------------------------------------ + +const sal_uInt32 ScaList::nStartSize = 16; +const sal_uInt32 ScaList::nIncrSize = 16; + +ScaList::ScaList() : + pData( new void*[ nStartSize ] ), + nSize( nStartSize ), + nCount( 0 ), + nCurr( 0 ) +{ +} + +ScaList::~ScaList() +{ + delete[] pData; +} + +void ScaList::_Grow() +{ + nSize += nIncrSize; + + void** pNewData = new void*[ nSize ]; + memcpy( pNewData, pData, nCount * sizeof( void* ) ); + + delete[] pData; + pData = pNewData; +} + +//------------------------------------------------------------------ + +ScaStringList::~ScaStringList() +{ + for( OUString* pStr = First(); pStr; pStr = Next() ) + delete pStr; +} + +//------------------------------------------------------------------ + +ScaResId::ScaResId( sal_uInt16 nId, ResMgr& rResMgr ) : + ResId( nId, rResMgr ) +{ +} + + +//------------------------------------------------------------------ + +#define UNIQUE sal_False // function name does not exist in Calc +#define DOUBLE sal_True // function name exists in Calc + +#define STDPAR sal_False // all parameters are described +#define INTPAR sal_True // first parameter is internal + +#define FUNCDATA( FuncName, ParamCount, Category, Double, IntPar ) \ + { "get" #FuncName, PRICING_FUNCNAME_##FuncName, PRICING_FUNCDESC_##FuncName, PRICING_DEFFUNCNAME_##FuncName, ParamCount, Category, Double, IntPar } + +const ScaFuncDataBase pFuncDataArr[] = +{ + FUNCDATA( Opt_barrier, 13, ScaCat_Finance, UNIQUE, STDPAR), + FUNCDATA( Opt_touch, 11, ScaCat_Finance, UNIQUE, STDPAR), + FUNCDATA( Opt_prob_hit, 6, ScaCat_Finance, UNIQUE, STDPAR), + FUNCDATA( Opt_prob_inmoney, 8, ScaCat_Finance, UNIQUE, STDPAR) +}; + +#undef FUNCDATA + + +//------------------------------------------------------------------ + +ScaFuncData::ScaFuncData( const ScaFuncDataBase& rBaseData, ResMgr& rResMgr ) : + aIntName( OUString::createFromAscii( rBaseData.pIntName ) ), + nUINameID( rBaseData.nUINameID ), + nDescrID( rBaseData.nDescrID ), + nCompListID( rBaseData.nCompListID ), + nParamCount( rBaseData.nParamCount ), + eCat( rBaseData.eCat ), + bDouble( rBaseData.bDouble ), + bWithOpt( rBaseData.bWithOpt ) +{ + ScaResStringArrLoader aArrLoader( RID_PRICING_DEFFUNCTION_NAMES, nCompListID, rResMgr ); + const ResStringArray& rArr = aArrLoader.GetStringArray(); + + for( sal_uInt16 nIndex = 0; nIndex < rArr.Count(); nIndex++ ) + aCompList.Append( rArr.GetString( nIndex ) ); +} + +ScaFuncData::~ScaFuncData() +{ +} + +sal_uInt16 ScaFuncData::GetStrIndex( sal_uInt16 nParam ) const +{ + if( !bWithOpt ) + nParam++; + return (nParam > nParamCount) ? (nParamCount * 2) : (nParam * 2); +} + + +//------------------------------------------------------------------ + +ScaFuncDataList::ScaFuncDataList( ResMgr& rResMgr ) : + nLast( 0xFFFFFFFF ) +{ + for( sal_uInt16 nIndex = 0; nIndex < SAL_N_ELEMENTS(pFuncDataArr); nIndex++ ) + Append( new ScaFuncData( pFuncDataArr[ nIndex ], rResMgr ) ); +} + +ScaFuncDataList::~ScaFuncDataList() +{ + for( ScaFuncData* pFData = First(); pFData; pFData = Next() ) + delete pFData; +} + +const ScaFuncData* ScaFuncDataList::Get( const OUString& rProgrammaticName ) const +{ + OUString aTestName; + + if( aLastName == rProgrammaticName ){ + return Get( nLast ); + } + + for( sal_uInt32 nIndex = 0; nIndex < Count(); nIndex++ ) + { + const ScaFuncData* pCurr = Get( nIndex ); + if( pCurr->Is( rProgrammaticName ) ) + { + const_cast< ScaFuncDataList* >( this )->aLastName = rProgrammaticName; + const_cast< ScaFuncDataList* >( this )->nLast = nIndex; + return pCurr; + } + } + return NULL; +} + + +//------------------------------------------------------------------ + +ScaFuncRes::ScaFuncRes( ResId& rResId, ResMgr& rResMgr, sal_uInt16 nIndex, OUString& rRet ) : + Resource( rResId ) +{ + rRet = String( ScaResId( nIndex, rResMgr ) ); + FreeResource(); +} + + +//------------------------------------------------------------------ +// +// entry points for service registration / instantiation +// +//------------------------------------------------------------------ + +uno::Reference< uno::XInterface > SAL_CALL ScaPricingAddIn_CreateInstance( + const uno::Reference< lang::XMultiServiceFactory >& ) +{ + static uno::Reference< uno::XInterface > xInst = (cppu::OWeakObject*) new ScaPricingAddIn(); + return xInst; +} + + +//------------------------------------------------------------------------ + +extern "C" { + +SAL_DLLPUBLIC_EXPORT void * SAL_CALL pricing_component_getFactory( + const sal_Char * pImplName, void * pServiceManager, void * /*pRegistryKey*/ ) +{ + void* pRet = 0; + + if ( pServiceManager && + OUString::createFromAscii( pImplName ) == ScaPricingAddIn::getImplementationName_Static() ) + { + uno::Reference< lang::XSingleServiceFactory > xFactory( cppu::createOneInstanceFactory( + reinterpret_cast< lang::XMultiServiceFactory* >( pServiceManager ), + ScaPricingAddIn::getImplementationName_Static(), + ScaPricingAddIn_CreateInstance, + ScaPricingAddIn::getSupportedServiceNames_Static() ) ); + + if (xFactory.is()) + { + xFactory->acquire(); + pRet = xFactory.get(); + } + } + + return pRet; +} + +} // extern C + +//------------------------------------------------------------------------ +// +// "normal" service implementation +// +//------------------------------------------------------------------------ + +ScaPricingAddIn::ScaPricingAddIn() : + pDefLocales( NULL ), + pResMgr( NULL ), + pFuncDataList( NULL ) +{ +} + +ScaPricingAddIn::~ScaPricingAddIn() +{ + if( pFuncDataList ) + delete pFuncDataList; + if( pDefLocales ) + delete[] pDefLocales; + + // pResMgr already deleted (_all_ resource managers are deleted _before_ this dtor is called) +} + +static const sal_Char* pLang[] = { "de", "en" }; +static const sal_Char* pCoun[] = { "DE", "US" }; +static const sal_uInt32 nNumOfLoc = SAL_N_ELEMENTS( pLang ); + +void ScaPricingAddIn::InitDefLocales() +{ + pDefLocales = new lang::Locale[ nNumOfLoc ]; + + for( sal_uInt32 nIndex = 0; nIndex < nNumOfLoc; nIndex++ ) + { + pDefLocales[ nIndex ].Language = OUString::createFromAscii( pLang[ nIndex ] ); + pDefLocales[ nIndex ].Country = OUString::createFromAscii( pCoun[ nIndex ] ); + } +} + +const lang::Locale& ScaPricingAddIn::GetLocale( sal_uInt32 nIndex ) +{ + if( !pDefLocales ) + InitDefLocales(); + + return (nIndex < sizeof( pLang )) ? pDefLocales[ nIndex ] : aFuncLoc; +} + +ResMgr& ScaPricingAddIn::GetResMgr() throw( uno::RuntimeException ) +{ + if( !pResMgr ) + { + InitData(); // try to get resource manager + if( !pResMgr ) + throw uno::RuntimeException(); + } + return *pResMgr; +} + +void ScaPricingAddIn::InitData() +{ + + if( pResMgr ) + delete pResMgr; + + OString aModName( "pricing" ); + pResMgr = ResMgr::CreateResMgr( aModName.getStr(), aFuncLoc ); + + if( pFuncDataList ) + delete pFuncDataList; + + pFuncDataList = pResMgr ? new ScaFuncDataList( *pResMgr ) : NULL; + + if( pDefLocales ) + { + delete pDefLocales; + pDefLocales = NULL; + } +} + +OUString ScaPricingAddIn::GetDisplFuncStr( sal_uInt16 nResId ) throw( uno::RuntimeException ) +{ + return ScaResStringLoader( RID_PRICING_FUNCTION_NAMES, nResId, GetResMgr() ).GetString(); +} + +OUString ScaPricingAddIn::GetFuncDescrStr( sal_uInt16 nResId, sal_uInt16 nStrIndex ) throw( uno::RuntimeException ) +{ + OUString aRet; + + ScaResPublisher aResPubl( ScaResId( RID_PRICING_FUNCTION_DESCRIPTIONS, GetResMgr() ) ); + ScaResId aResId( nResId, GetResMgr() ); + aResId.SetRT( RSC_RESOURCE ); + + if( aResPubl.IsAvailableRes( aResId ) ) + ScaFuncRes aSubRes( aResId, GetResMgr(), nStrIndex, aRet ); + + aResPubl.FreeResource(); + return aRet; +} + + +//------------------------------------------------------------------------ + +OUString ScaPricingAddIn::getImplementationName_Static() +{ + return OUString(RTL_CONSTASCII_USTRINGPARAM( MY_IMPLNAME )); +} + +uno::Sequence< OUString > ScaPricingAddIn::getSupportedServiceNames_Static() +{ + uno::Sequence< OUString > aRet( 2 ); + OUString* pArray = aRet.getArray(); + pArray[0] = OUString(RTL_CONSTASCII_USTRINGPARAM( ADDIN_SERVICE )); + pArray[1] = OUString(RTL_CONSTASCII_USTRINGPARAM( MY_SERVICE )); + return aRet; +} + +// XServiceName + +OUString SAL_CALL ScaPricingAddIn::getServiceName() throw( uno::RuntimeException ) +{ + // name of specific AddIn service + return OUString(RTL_CONSTASCII_USTRINGPARAM( MY_SERVICE )); +} + +// XServiceInfo + +OUString SAL_CALL ScaPricingAddIn::getImplementationName() throw( uno::RuntimeException ) +{ + return getImplementationName_Static(); +} + +sal_Bool SAL_CALL ScaPricingAddIn::supportsService( const OUString& aServiceName ) throw( uno::RuntimeException ) +{ + return aServiceName == ADDIN_SERVICE || aServiceName == MY_SERVICE; +} + +uno::Sequence< OUString > SAL_CALL ScaPricingAddIn::getSupportedServiceNames() throw( uno::RuntimeException ) +{ + return getSupportedServiceNames_Static(); +} + +// XLocalizable + +void SAL_CALL ScaPricingAddIn::setLocale( const lang::Locale& eLocale ) throw( uno::RuntimeException ) +{ + aFuncLoc = eLocale; + InitData(); // change of locale invalidates resources! +} + +lang::Locale SAL_CALL ScaPricingAddIn::getLocale() throw( uno::RuntimeException ) +{ + return aFuncLoc; +} + +//------------------------------------------------------------------ +// +// function descriptions start here +// +//------------------------------------------------------------------ + +// XAddIn +OUString SAL_CALL ScaPricingAddIn::getProgrammaticFuntionName( const OUString& ) throw( uno::RuntimeException ) +{ + // not used by calc + // (but should be implemented for other uses of the AddIn service) + return OUString(); +} + +OUString SAL_CALL ScaPricingAddIn::getDisplayFunctionName( const OUString& aProgrammaticName ) throw( uno::RuntimeException ) +{ + OUString aRet; + + const ScaFuncData* pFData = pFuncDataList->Get( aProgrammaticName ); + if( pFData ) + { + aRet = GetDisplFuncStr( pFData->GetUINameID() ); + if( pFData->IsDouble() ) + aRet += STR_FROM_ANSI( "_ADD" ); + } + else + { + aRet = STR_FROM_ANSI( "UNKNOWNFUNC_" ); + aRet += aProgrammaticName; + } + + return aRet; +} + +OUString SAL_CALL ScaPricingAddIn::getFunctionDescription( const OUString& aProgrammaticName ) throw( uno::RuntimeException ) +{ + OUString aRet; + + const ScaFuncData* pFData = pFuncDataList->Get( aProgrammaticName ); + if( pFData ) + aRet = GetFuncDescrStr( pFData->GetDescrID(), 1 ); + + return aRet; +} + +OUString SAL_CALL ScaPricingAddIn::getDisplayArgumentName( + const OUString& aProgrammaticName, sal_Int32 nArgument ) throw( uno::RuntimeException ) +{ + OUString aRet; + + const ScaFuncData* pFData = pFuncDataList->Get( aProgrammaticName ); + if( pFData && (nArgument <= 0xFFFF) ) + { + sal_uInt16 nStr = pFData->GetStrIndex( static_cast< sal_uInt16 >( nArgument ) ); + if( nStr ) + aRet = GetFuncDescrStr( pFData->GetDescrID(), nStr ); + else + aRet = STR_FROM_ANSI( "internal" ); + } + + return aRet; +} + +OUString SAL_CALL ScaPricingAddIn::getArgumentDescription( + const OUString& aProgrammaticName, sal_Int32 nArgument ) throw( uno::RuntimeException ) +{ + OUString aRet; + + const ScaFuncData* pFData = pFuncDataList->Get( aProgrammaticName ); + if( pFData && (nArgument <= 0xFFFF) ) + { + sal_uInt16 nStr = pFData->GetStrIndex( static_cast< sal_uInt16 >( nArgument ) ); + if( nStr ) + aRet = GetFuncDescrStr( pFData->GetDescrID(), nStr + 1 ); + else + aRet = STR_FROM_ANSI( "for internal use only" ); + } + + return aRet; +} + +OUString SAL_CALL ScaPricingAddIn::getProgrammaticCategoryName( + const OUString& aProgrammaticName ) throw( uno::RuntimeException ) +{ + OUString aRet; + + const ScaFuncData* pFData = pFuncDataList->Get( aProgrammaticName ); + if( pFData ) + { + switch( pFData->GetCategory() ) + { + case ScaCat_DateTime: aRet = STR_FROM_ANSI( "Date&Time" ); break; + case ScaCat_Text: aRet = STR_FROM_ANSI( "Text" ); break; + case ScaCat_Finance: aRet = STR_FROM_ANSI( "Financial" ); break; + case ScaCat_Inf: aRet = STR_FROM_ANSI( "Information" ); break; + case ScaCat_Math: aRet = STR_FROM_ANSI( "Mathematical" ); break; + case ScaCat_Tech: aRet = STR_FROM_ANSI( "Technical" ); break; + default: // to prevent compiler warnings + break; + } + } + + if( aRet.isEmpty() ) + aRet = STR_FROM_ANSI( "Add-In" ); + return aRet; +} + +OUString SAL_CALL ScaPricingAddIn::getDisplayCategoryName( + const OUString& aProgrammaticName ) throw( uno::RuntimeException ) +{ + return getProgrammaticCategoryName( aProgrammaticName ); +} + + +// XCompatibilityNames + +uno::Sequence< sheet::LocalizedName > SAL_CALL ScaPricingAddIn::getCompatibilityNames( + const OUString& aProgrammaticName ) throw( uno::RuntimeException ) +{ + const ScaFuncData* pFData = pFuncDataList->Get( aProgrammaticName ); + if( !pFData ) + return uno::Sequence< sheet::LocalizedName >( 0 ); + + const ScaStringList& rStrList = pFData->GetCompNameList(); + sal_uInt32 nCount = rStrList.Count(); + + uno::Sequence< sheet::LocalizedName > aRet( nCount ); + sheet::LocalizedName* pArray = aRet.getArray(); + + for( sal_uInt32 nIndex = 0; nIndex < nCount; nIndex++ ) + pArray[ nIndex ] = sheet::LocalizedName( GetLocale( nIndex ), *rStrList.Get( nIndex ) ); + + return aRet; +} + + + +// --------------------------------------------------------------------- +// --------------------------------------------------------------------- +// actual function implementation starts here +// + +// auxillary input handling functions +namespace { + +bool getinput_putcall(bs::types::PutCall& pc, const STRING& str) { + if(str.compareToAscii("c",1)==0) { + pc=bs::types::Call; + } else if(str.compareToAscii("p",1)==0) { + pc=bs::types::Put; + } else { + return false; + } + return true; +} + +bool getinput_putcall(bs::types::PutCall& pc, const ANY& anyval) { + STRING str; + if(anyval.getValueTypeClass() == ::com::sun::star::uno::TypeClass_STRING) { + anyval >>= str; + } else if(anyval.getValueTypeClass() == ::com::sun::star::uno::TypeClass_VOID) { + str="c"; // call as default + } else { + return false; + } + return getinput_putcall(pc, str); +} + +bool getinput_strike(double& strike, const ANY& anyval) { + if(anyval.getValueTypeClass() == ::com::sun::star::uno::TypeClass_DOUBLE) { + anyval >>= strike; + } else if(anyval.getValueTypeClass() == ::com::sun::star::uno::TypeClass_VOID) { + strike=-1.0; // -1 as default (means not set) + } else { + return false; + } + return true; +} + +bool getinput_inout(bs::types::BarrierKIO& kio, const STRING& str) { + if(str.compareToAscii("i",1)==0) { + kio=bs::types::KnockIn; + } else if(str.compareToAscii("o",1)==0) { + kio=bs::types::KnockOut; + } else { + return false; + } + return true; +} + +bool getinput_barrier(bs::types::BarrierActive& cont, const STRING& str) { + if(str.compareToAscii("c",1)==0) { + cont=bs::types::Continuous; + } else if(str.compareToAscii("e",1)==0) { + cont=bs::types::Maturity; + } else { + return false; + } + return true; +} + +bool getinput_fordom(bs::types::ForDom& fd, const STRING& str) { + if(str.compareToAscii("f",1)==0) { + fd=bs::types::Foreign; + } else if(str.compareToAscii("d",1)==0) { + fd=bs::types::Domestic; + } else { + return false; + } + return true; +} + +bool getinput_greek(bs::types::Greeks& greek, const ANY& anyval) { + STRING str; + if(anyval.getValueTypeClass() == ::com::sun::star::uno::TypeClass_STRING) { + anyval >>= str; + } else if(anyval.getValueTypeClass() == ::com::sun::star::uno::TypeClass_VOID) { + str="value"; + } else { + return false; + } + + if(str.compareToAscii("value")==0 || str.compareToAscii("price")==0 || + str.compareToAscii("v")==0 || str.compareToAscii("p")==0 ) { + greek=bs::types::Value; + } else if(str.compareToAscii("delta")==0||str.compareToAscii("d")==0) { + greek=bs::types::Delta; + } else if(str.compareToAscii("gamma")==0||str.compareToAscii("g")==0) { + greek=bs::types::Gamma; + } else if(str.compareToAscii("theta")==0||str.compareToAscii("t")==0) { + greek=bs::types::Theta; + } else if(str.compareToAscii("vega")==0||str.compareToAscii("e")==0) { + greek=bs::types::Vega; + } else if(str.compareToAscii("volga")==0||str.compareToAscii("o")==0) { + greek=bs::types::Volga; + } else if(str.compareToAscii("vanna")==0||str.compareToAscii("a")==0) { + greek=bs::types::Vanna; + } else if(str.compareToAscii("rho")==0||str.compareToAscii("r")==0) { + greek=bs::types::Rho_d; + } else if(str.compareToAscii("rhof")==0||str.compareToAscii("f")==0) { + greek=bs::types::Rho_f; + } else { + return false; + } + return true; +} + +} // namespace for auxillary functions + + +// OPT_BARRIER(...) +double SAL_CALL ScaPricingAddIn::getOpt_barrier( double spot, double vol, + double r, double rf, double T, double strike, + double barrier_low, double barrier_up, double rebate, + const STRING& put_call, const STRING& in_out, + const STRING& barriercont, const ANY& greekstr ) THROWDEF_RTE_IAE +{ + bs::types::PutCall pc; + bs::types::BarrierKIO kio; + bs::types::BarrierActive bcont; + bs::types::Greeks greek; + // read and check input values + if( spot<=0.0 || vol<=0.0 || T<0.0 || strike<0.0 || + !getinput_putcall(pc,put_call) || + !getinput_inout(kio,in_out) || + !getinput_barrier(bcont,barriercont) || + !getinput_greek(greek,greekstr) ){ + THROW_IAE; + } + + double fRet=bs::barrier(spot,vol,r,rf,T,strike, barrier_low,barrier_up, + rebate,pc,kio,bcont,greek); + + RETURN_FINITE( fRet ); +} + +// OPT_TOUCH(...) +double SAL_CALL ScaPricingAddIn::getOpt_touch( double spot, double vol, + double r, double rf, double T, + double barrier_low, double barrier_up, + const STRING& for_dom, const STRING& in_out, + const STRING& barriercont, const ANY& greekstr ) THROWDEF_RTE_IAE +{ + bs::types::ForDom fd; + bs::types::BarrierKIO kio; + bs::types::BarrierActive bcont; + bs::types::Greeks greek; + // read and check input values + if( spot<=0.0 || vol<=0.0 || T<0.0 || + !getinput_fordom(fd,for_dom) || + !getinput_inout(kio,in_out) || + !getinput_barrier(bcont,barriercont) || + !getinput_greek(greek,greekstr) ){ + THROW_IAE; + } + + double fRet=bs::touch(spot,vol,r,rf,T,barrier_low,barrier_up, + fd,kio,bcont,greek); + + RETURN_FINITE( fRet ); +} + +// OPT_PRB_HIT(...) +double SAL_CALL ScaPricingAddIn::getOpt_prob_hit( double spot, double vol, + double mu, double T, + double barrier_low, double barrier_up ) THROWDEF_RTE_IAE +{ + // read and check input values + if( spot<=0.0 || vol<=0.0 || T<0.0 ) { + THROW_IAE; + } + + double fRet=bs::prob_hit(spot,vol,mu,T,barrier_low,barrier_up); + + RETURN_FINITE( fRet ); +} + +// OPT_PRB_INMONEY(...) +double SAL_CALL ScaPricingAddIn::getOpt_prob_inmoney( double spot, double vol, + double mu, double T, + double barrier_low, double barrier_up, + const ANY& strikeval, const ANY& put_call ) THROWDEF_RTE_IAE +{ + bs::types::PutCall pc; + double K; + + // read and check input values + if( spot<=0.0 || vol<=0.0 || T<0.0 || + !getinput_putcall(pc,put_call) || + !getinput_strike(K,strikeval) ) { + THROW_IAE; + } + + double fRet=bs::prob_in_money(spot,vol,mu,T,K,barrier_low,barrier_up,pc); + + RETURN_FINITE( fRet ); +} + + + +//------------------------------------------------------------------ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/scaddins/source/pricing/pricing.hrc b/scaddins/source/pricing/pricing.hrc new file mode 100644 index 000000000000..bf4df2183847 --- /dev/null +++ b/scaddins/source/pricing/pricing.hrc @@ -0,0 +1,54 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef _SCA_PRICING_HRC +#define _SCA_PRICING_HRC + + +#define PRICING_RESOURCE_START 1000 + +#define RID_PRICING_FUNCTION_DESCRIPTIONS PRICING_RESOURCE_START +#define RID_PRICING_FUNCTION_NAMES (PRICING_RESOURCE_START+1000) +#define RID_PRICING_DEFFUNCTION_NAMES (PRICING_RESOURCE_START+2000) + + +#define PRICING_FUNCDESC_START (RID_PRICING_FUNCTION_DESCRIPTIONS+1) + +#define PRICING_FUNCDESC_Opt_barrier (PRICING_FUNCDESC_START) +#define PRICING_FUNCDESC_Opt_touch (PRICING_FUNCDESC_START+1) +#define PRICING_FUNCDESC_Opt_prob_hit (PRICING_FUNCDESC_START+2) +#define PRICING_FUNCDESC_Opt_prob_inmoney (PRICING_FUNCDESC_START+3) + + +#define PRICING_FUNCNAME_START (RID_PRICING_FUNCTION_NAMES+1) + +#define PRICING_FUNCNAME_Opt_barrier (PRICING_FUNCNAME_START) +#define PRICING_FUNCNAME_Opt_touch (PRICING_FUNCNAME_START+1) +#define PRICING_FUNCNAME_Opt_prob_hit (PRICING_FUNCNAME_START+2) +#define PRICING_FUNCNAME_Opt_prob_inmoney (PRICING_FUNCNAME_START+3) + + +#define PRICING_DEFFUNCNAME_START (RID_PRICING_DEFFUNCTION_NAMES+1) + +#define PRICING_DEFFUNCNAME_Opt_barrier (PRICING_DEFFUNCNAME_START) +#define PRICING_DEFFUNCNAME_Opt_touch (PRICING_DEFFUNCNAME_START+1) +#define PRICING_DEFFUNCNAME_Opt_prob_hit (PRICING_DEFFUNCNAME_START+2) +#define PRICING_DEFFUNCNAME_Opt_prob_inmoney (PRICING_DEFFUNCNAME_START+3) + + +#endif diff --git a/scaddins/source/pricing/pricing.hxx b/scaddins/source/pricing/pricing.hxx new file mode 100644 index 000000000000..66d2d26618b0 --- /dev/null +++ b/scaddins/source/pricing/pricing.hxx @@ -0,0 +1,418 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +//------------------------------------------------------------------ +// +// option pricing functions add in +// +// most parts of this files are technical UNO details which are +// all copied from ../datefunc/datefunc.hxx +// to avoid having to rename all classes to do with UNO +// technicalities we use our own namespace +// +//------------------------------------------------------------------ + +#ifndef _SCA_PRICING_HXX +#define _SCA_PRICING_HXX + + +#include <string.h> +#include <com/sun/star/lang/XServiceName.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/sheet/XAddIn.hpp> +#include <com/sun/star/sheet/XCompatibilityNames.hpp> +#include <com/sun/star/sheet/addin/XPricingFunctions.hpp> +#include <cppuhelper/implbase5.hxx> // helper for implementations +#include <tools/resid.hxx> +#include <tools/rc.hxx> +#include <tools/resary.hxx> + +#define ANY ::com::sun::star::uno::Any +#define STRING ::rtl::OUString +#define THROWDEF_RTE_IAE throw(::com::sun::star::uno::RuntimeException,::com::sun::star::lang::IllegalArgumentException) +#define THROW_IAE throw ::com::sun::star::lang::IllegalArgumentException() +#define RETURN_FINITE(d) if( ::rtl::math::isFinite( d ) ) return d; else THROW_IAE + + + +//------------------------------------------------------------------ + +namespace sca { +namespace pricing { + +class ScaList +{ +private: + static const sal_uInt32 nStartSize; + static const sal_uInt32 nIncrSize; + + void** pData; // pointer array + sal_uInt32 nSize; // array size + sal_uInt32 nCount; // next index to be inserted at + sal_uInt32 nCurr; // current pos for iterations + + void _Grow(); + inline void Grow(); + +public: + ScaList(); + virtual ~ScaList(); + + inline sal_uInt32 Count() const { return nCount; } + + inline const void* GetObject( sal_uInt32 nIndex ) const + { return (nIndex < nCount) ? pData[ nIndex ] : NULL; } + + inline void* First() { return nCount ? pData[ nCurr = 0 ] : NULL; } + inline void* Next() { return (nCurr + 1 < nCount) ? pData[ ++nCurr ] : NULL; } + + inline void Append( void* pNew ); +}; + + +inline void ScaList::Grow() +{ + if( nCount >= nSize ) + _Grow(); +} + +inline void ScaList::Append( void* pNew ) +{ + Grow(); + pData[ nCount++ ] = pNew; +} + + +//------------------------------------------------------------------ + +class ScaStringList : protected ScaList +{ +public: + inline ScaStringList() : ScaList() {}; + virtual ~ScaStringList(); + + using ScaList::Count; + + inline const ::rtl::OUString* Get( sal_uInt32 nIndex ) const; + + inline ::rtl::OUString* First(); + inline ::rtl::OUString* Next(); + + using ScaList::Append; + inline void Append( ::rtl::OUString* pNew ); + inline void Append( const ::rtl::OUString& rNew ); +}; + + +inline const ::rtl::OUString* ScaStringList::Get( sal_uInt32 nIndex ) const +{ + return static_cast< const ::rtl::OUString* >( ScaList::GetObject( nIndex ) ); +} + +inline ::rtl::OUString* ScaStringList::First() +{ + return static_cast< ::rtl::OUString* >( ScaList::First() ); +} + +inline ::rtl::OUString* ScaStringList::Next() +{ + return static_cast< ::rtl::OUString* >( ScaList::Next() ); +} + +inline void ScaStringList::Append( ::rtl::OUString* pNew ) +{ + ScaList::Append( pNew ); +} + +inline void ScaStringList::Append( const ::rtl::OUString& rNew ) +{ + ScaList::Append( new ::rtl::OUString( rNew ) ); +} + + +//------------------------------------------------------------------ + +class ScaResId : public ResId +{ +public: + ScaResId( sal_uInt16 nResId, ResMgr& rResMgr ); +}; + + +//------------------------------------------------------------------ + +class ScaResStringLoader : public Resource +{ +private: + String aStr; + +public: + inline ScaResStringLoader( sal_uInt16 nResId, sal_uInt16 nStrId, ResMgr& rResMgr ); + + inline const String& GetString() const { return aStr; } + +}; + + +inline ScaResStringLoader::ScaResStringLoader( sal_uInt16 nResId, sal_uInt16 nStrId, ResMgr& rResMgr ) : + Resource( ScaResId( nResId, rResMgr ) ), + aStr( ScaResId( nStrId, rResMgr ) ) +{ + FreeResource(); +} + + +//------------------------------------------------------------------ + +class ScaResStringArrLoader : public Resource +{ +private: + ResStringArray aStrArray; + +public: + inline ScaResStringArrLoader( sal_uInt16 nResId, sal_uInt16 nArrayId, ResMgr& rResMgr ); + + inline const ResStringArray& GetStringArray() const { return aStrArray; } +}; + + + +inline ScaResStringArrLoader::ScaResStringArrLoader( sal_uInt16 nResId, sal_uInt16 nArrayId, ResMgr& rResMgr ) : + Resource( ScaResId( nResId, rResMgr ) ), + aStrArray( ScaResId( nArrayId, rResMgr ) ) +{ + FreeResource(); +} + + +//------------------------------------------------------------------ + +class ScaResPublisher : public Resource +{ +public: + inline ScaResPublisher( const ScaResId& rResId ) : Resource( rResId ) {} + + inline sal_Bool IsAvailableRes( const ResId& rResId ) const + { return Resource::IsAvailableRes( rResId ); } + inline void FreeResource() + { Resource::FreeResource(); } +}; + + +//------------------------------------------------------------------ + +class ScaFuncRes : public Resource +{ +public: + ScaFuncRes( ResId& rResId, ResMgr& rResMgr, sal_uInt16 nIndex, ::rtl::OUString& rRet ); +}; + + +//------------------------------------------------------------------ + +enum ScaCategory +{ + ScaCat_AddIn, + ScaCat_DateTime, + ScaCat_Text, + ScaCat_Finance, + ScaCat_Inf, + ScaCat_Math, + ScaCat_Tech +}; + +struct ScaFuncDataBase +{ + const sal_Char* pIntName; // internal name (get***) + sal_uInt16 nUINameID; // resource ID to UI name + sal_uInt16 nDescrID; // resource ID to description, parameter names and ~ description + sal_uInt16 nCompListID; // resource ID to list of valid names + sal_uInt16 nParamCount; // number of named / described parameters + ScaCategory eCat; // function category + sal_Bool bDouble; // name already exist in Calc + sal_Bool bWithOpt; // first parameter is internal +}; + +class ScaFuncData +{ +private: + ::rtl::OUString aIntName; // internal name (get***) + sal_uInt16 nUINameID; // resource ID to UI name + sal_uInt16 nDescrID; // leads also to parameter descriptions! + sal_uInt16 nCompListID; // resource ID to list of valid names + sal_uInt16 nParamCount; // num of parameters + ScaStringList aCompList; // list of all valid names + ScaCategory eCat; // function category + sal_Bool bDouble; // name already exist in Calc + sal_Bool bWithOpt; // first parameter is internal + +public: + ScaFuncData( const ScaFuncDataBase& rBaseData, ResMgr& rRscMgr ); + virtual ~ScaFuncData(); + + inline sal_uInt16 GetUINameID() const { return nUINameID; } + inline sal_uInt16 GetDescrID() const { return nDescrID; } + inline ScaCategory GetCategory() const { return eCat; } + inline sal_Bool IsDouble() const { return bDouble; } + inline sal_Bool HasIntParam() const { return bWithOpt; } + + sal_uInt16 GetStrIndex( sal_uInt16 nParam ) const; + inline sal_Bool Is( const ::rtl::OUString& rCompare ) const + { return aIntName == rCompare; } + + inline const ScaStringList& GetCompNameList() const { return aCompList; } +}; + + +//------------------------------------------------------------------ + +class ScaFuncDataList : private ScaList +{ + ::rtl::OUString aLastName; + sal_uInt32 nLast; + +public: + ScaFuncDataList( ResMgr& rResMgr ); + virtual ~ScaFuncDataList(); + + using ScaList::Count; + + inline const ScaFuncData* Get( sal_uInt32 nIndex ) const; + const ScaFuncData* Get( const ::rtl::OUString& rProgrammaticName ) const; + inline ScaFuncData* First(); + inline ScaFuncData* Next(); + + using ScaList::Append; + inline void Append( ScaFuncData* pNew ) { ScaList::Append( pNew ); } +}; + + +inline const ScaFuncData* ScaFuncDataList::Get( sal_uInt32 nIndex ) const +{ + return static_cast< const ScaFuncData* >( ScaList::GetObject( nIndex ) ); +} + +inline ScaFuncData* ScaFuncDataList::First() +{ + return static_cast< ScaFuncData* >( ScaList::First() ); +} + +inline ScaFuncData* ScaFuncDataList::Next() +{ + return static_cast< ScaFuncData* >( ScaList::Next() ); +} + +} // namespace pricing +} // namespace sca + + + +//------------------------------------------------------------------ +//------------------------------------------------------------------ + +::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL PricingFunctionAddIn_CreateInstance( + const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& ); + + +// AddIn class for pricing functions + +class ScaPricingAddIn : public ::cppu::WeakImplHelper5< + ::com::sun::star::sheet::XAddIn, + ::com::sun::star::sheet::XCompatibilityNames, + ::com::sun::star::sheet::addin::XPricingFunctions, + ::com::sun::star::lang::XServiceName, + ::com::sun::star::lang::XServiceInfo > +{ +private: + ::com::sun::star::lang::Locale aFuncLoc; + ::com::sun::star::lang::Locale* pDefLocales; + ResMgr* pResMgr; + sca::pricing::ScaFuncDataList* pFuncDataList; + + + void InitDefLocales(); + const ::com::sun::star::lang::Locale& GetLocale( sal_uInt32 nIndex ); + ResMgr& GetResMgr() throw( ::com::sun::star::uno::RuntimeException ); + void InitData(); + + ::rtl::OUString GetDisplFuncStr( sal_uInt16 nResId ) throw( ::com::sun::star::uno::RuntimeException ); + ::rtl::OUString GetFuncDescrStr( sal_uInt16 nResId, sal_uInt16 nStrIndex ) throw( ::com::sun::star::uno::RuntimeException ); + +public: + ScaPricingAddIn(); + virtual ~ScaPricingAddIn(); + + static ::rtl::OUString getImplementationName_Static(); + static ::com::sun::star::uno::Sequence< ::rtl::OUString > getSupportedServiceNames_Static(); + + // XAddIn + virtual ::rtl::OUString SAL_CALL getProgrammaticFuntionName( const ::rtl::OUString& aDisplayName ) throw( ::com::sun::star::uno::RuntimeException ); + virtual ::rtl::OUString SAL_CALL getDisplayFunctionName( const ::rtl::OUString& aProgrammaticName ) throw( ::com::sun::star::uno::RuntimeException ); + virtual ::rtl::OUString SAL_CALL getFunctionDescription( const ::rtl::OUString& aProgrammaticName ) throw( ::com::sun::star::uno::RuntimeException ); + virtual ::rtl::OUString SAL_CALL getDisplayArgumentName( const ::rtl::OUString& aProgrammaticName, sal_Int32 nArgument ) throw( ::com::sun::star::uno::RuntimeException ); + virtual ::rtl::OUString SAL_CALL getArgumentDescription( const ::rtl::OUString& aProgrammaticName, sal_Int32 nArgument ) throw( ::com::sun::star::uno::RuntimeException ); + virtual ::rtl::OUString SAL_CALL getProgrammaticCategoryName( const ::rtl::OUString& aProgrammaticName ) throw( ::com::sun::star::uno::RuntimeException ); + virtual ::rtl::OUString SAL_CALL getDisplayCategoryName( const ::rtl::OUString& aProgrammaticName ) throw( ::com::sun::star::uno::RuntimeException ); + + // XCompatibilityNames + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::sheet::LocalizedName > SAL_CALL getCompatibilityNames( const ::rtl::OUString& aProgrammaticName ) throw( ::com::sun::star::uno::RuntimeException ); + + // XLocalizable + virtual void SAL_CALL setLocale( const ::com::sun::star::lang::Locale& eLocale ) throw( ::com::sun::star::uno::RuntimeException ); + virtual ::com::sun::star::lang::Locale SAL_CALL getLocale() throw( ::com::sun::star::uno::RuntimeException ); + + // XServiceName + virtual ::rtl::OUString SAL_CALL getServiceName() throw( ::com::sun::star::uno::RuntimeException ); + + // XServiceInfo + virtual ::rtl::OUString SAL_CALL getImplementationName() throw( ::com::sun::star::uno::RuntimeException ); + virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) throw( ::com::sun::star::uno::RuntimeException ); + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames() throw( ::com::sun::star::uno::RuntimeException ); + + // ---------------------------------------- + // methods from own interfaces start here + // ---------------------------------------- + + virtual double SAL_CALL getOpt_barrier( double spot, double vol, + double r, double rf, double T, double strike, + double barrier_low, double barrier_up, double rebate, + const STRING& put_call, const STRING& in_out, + const STRING& continuous, const ANY& greek ) THROWDEF_RTE_IAE; + + virtual double SAL_CALL getOpt_touch( double spot, double vol, + double r, double rf, double T, + double barrier_low, double barrier_up, + const STRING& for_dom, const STRING& in_out, + const STRING& barriercont, const ANY& greekstr ) THROWDEF_RTE_IAE; + + virtual double SAL_CALL getOpt_prob_hit( double spot, double vol, + double mu, double T, + double barrier_low, double barrier_up ) THROWDEF_RTE_IAE; + + virtual double SAL_CALL getOpt_prob_inmoney( double spot, double vol, + double mu, double T, + double barrier_low, double barrier_up, + const ANY& strikeval, const ANY& put_call ) THROWDEF_RTE_IAE; + +}; +//------------------------------------------------------------------ + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/scaddins/source/pricing/pricing.src b/scaddins/source/pricing/pricing.src new file mode 100644 index 000000000000..c85a5d59aec5 --- /dev/null +++ b/scaddins/source/pricing/pricing.src @@ -0,0 +1,436 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include "pricing.hrc" + + +// function and parameter description +Resource RID_PRICING_FUNCTION_DESCRIPTIONS +{ + Resource PRICING_FUNCDESC_Opt_barrier + { + String 1 // description + { + Text [ en-US ] = "pricing of a barrier option"; + }; + + String 2 // name of parameter 1 + { + Text [ en-US ] = "spot"; + }; + String 3 // description of parameter 1 + { + Text [ en-US ] = "price/value of the underlying asset"; + }; + + String 4 // name of parameter 2 + { + Text [ en-US ] = "vol"; + }; + String 5 // description of parameter 2 + { + Text [ en-US ] = "annual volatility of the underlying asset"; + }; + + String 6 // name of parameter 3 + { + Text [ en-US ] = "r"; + }; + String 7 // description of parameter 3 + { + Text [ en-US ] = "interest rate (continuously compounded)"; + }; + + String 8 // name of parameter 4 + { + Text [ en-US ] = "rf"; + }; + String 9 // description of parameter 4 + { + Text [ en-US ] = "foreign interest rate (continuously compounded)"; + }; + + String 10 // name of parameter 5 + { + Text [ en-US ] = "T"; + }; + String 11 // description of parameter 5 + { + Text [ en-US ] = "time to maturity of the option in years"; + }; + + String 12 // name of parameter 6 + { + Text [ en-US ] = "strike"; + }; + String 13 // description of parameter 6 + { + Text [ en-US ] = "strike level of the option"; + }; + + String 14 // name of parameter 7 + { + Text [ en-US ] = "barrier_low"; + }; + String 15 // description of parameter 7 + { + Text [ en-US ] = "lower barrier (set to 0 for no lower barrier)"; + }; + + String 16 // name of parameter 8 + { + Text [ en-US ] = "barrier_up"; + }; + String 17 // description of parameter 8 + { + Text [ en-US ] = "upper barrier (set to 0 for no upper barrier)"; + }; + + String 18 // name of parameter 8 + { + Text [ en-US ] = "rebate"; + }; + String 19 // description of parameter 8 + { + Text [ en-US ] = "amount of money paid at maturity if barrier was hit"; + }; + + String 20 // name of parameter 10 + { + Text [ en-US ] = "put/call"; + }; + String 21 // description of parameter 10 + { + Text [ en-US ] = "string to define if the option is a (p)ut or a (c)all"; + }; + + String 22 // name of parameter 11 + { + Text [ en-US ] = "knock in/out"; + }; + String 23 // description of parameter 11 + { + Text [ en-US ] = "string to define if the option is of type knock-(i)n or knock-(o)ut"; + }; + + String 24 // name of parameter 12 + { + Text [ en-US ] = "barrier_type"; + }; + String 25 // description of parameter 12 + { + Text [ en-US ] = "string to define whether the barrier is observed (c)ontinuously or only at the (e)nd/maturity"; + }; + + String 26 // name of parameter 13 + { + Text [ en-US ] = "greek"; + }; + String 27 // description of parameter 13 + { + Text [ en-US ] = "optional parameter, if left out then the function simply returns the option price; if set, the function returns price sensitivities (Greeks) to one of the input parameters; possible values are (d)elta, (g)amma, (t)heta, v(e)ga, v(o)lga, v(a)nna, (r)ho, rho(f)"; + }; + }; + + + + Resource PRICING_FUNCDESC_Opt_touch + { + String 1 // description + { + Text [ en-US ] = "pricing of a touch/no-touch option"; + }; + + String 2 // name of parameter 1 + { + Text [ en-US ] = "spot"; + }; + String 3 // description of parameter 1 + { + Text [ en-US ] = "price/value of the underlying asset"; + }; + + String 4 // name of parameter 2 + { + Text [ en-US ] = "vol"; + }; + String 5 // description of parameter 2 + { + Text [ en-US ] = "annual volatility of the underlying asset"; + }; + + String 6 // name of parameter 3 + { + Text [ en-US ] = "r"; + }; + String 7 // description of parameter 3 + { + Text [ en-US ] = "interest rate (continuously compounded)"; + }; + + String 8 // name of parameter 4 + { + Text [ en-US ] = "rf"; + }; + String 9 // description of parameter 4 + { + Text [ en-US ] = "foreign interest rate (continuously compounded)"; + }; + + String 10 // name of parameter 5 + { + Text [ en-US ] = "T"; + }; + String 11 // description of parameter 5 + { + Text [ en-US ] = "time to maturity of the option in years"; + }; + + String 12 // name of parameter 6 + { + Text [ en-US ] = "barrier_low"; + }; + String 13 // description of parameter 6 + { + Text [ en-US ] = "lower barrier (set to 0 for no lower barrier)"; + }; + + String 14 // name of parameter 7 + { + Text [ en-US ] = "barrier_up"; + }; + String 15 // description of parameter 7 + { + Text [ en-US ] = "upper barrier (set to 0 for no upper barrier)"; + }; + + String 16 // name of parameter 8 + { + Text [ en-US ] = "foreign/domestic"; + }; + String 17 // description of parameter 8 + { + Text [ en-US ] = "string to define if the option pays one unit of (d)omestic currency (cash or nothing) or (f)oreign currency (asset or nothing)"; + }; + + String 18 // name of parameter 9 + { + Text [ en-US ] = "knock in/out"; + }; + String 19 // description of parameter 9 + { + Text [ en-US ] = "string to define if the option is of type knock-(i)n (touch) or knock-(o)ut (no-touch)"; + }; + + String 20 // name of parameter 10 + { + Text [ en-US ] = "barrier_type"; + }; + String 21 // description of parameter 10 + { + Text [ en-US ] = "string to define whether the barrier is observed (c)ontinuously or only at the (e)nd/maturity"; + }; + + String 22 // name of parameter 11 + { + Text [ en-US ] = "greek"; + }; + String 23 // description of parameter 11 + { + Text [ en-US ] = "optional parameter, if left out then the function simply returns the option price; if set, the function returns price sensitivities (Greeks) to one of the input parameters; possible values are (d)elta, (g)amma, (t)heta, v(e)ga, v(o)lga, v(a)nna, (r)ho, rho(f)"; + }; + }; + + + Resource PRICING_FUNCDESC_Opt_prob_hit + { + String 1 // description + { + Text [ en-US ] = "probability that an asset hits a barrier assuming it follows dS/S = mu dt + vol dW"; + }; + + String 2 // name of parameter 1 + { + Text [ en-US ] = "spot"; + }; + String 3 // description of parameter 1 + { + Text [ en-US ] = "price/value S of the underlying asset"; + }; + + String 4 // name of parameter 2 + { + Text [ en-US ] = "vol"; + }; + String 5 // description of parameter 2 + { + Text [ en-US ] = "annual volatility of the underlying asset"; + }; + + String 6 // name of parameter 3 + { + Text [ en-US ] = "drift"; + }; + String 7 // description of parameter 3 + { + Text [ en-US ] = "parameter mu in dS/S = mu dt + vol dW"; + }; + + String 8 // name of parameter 4 + { + Text [ en-US ] = "T"; + }; + String 9 // description of parameter 4 + { + Text [ en-US ] = "time to maturity"; + }; + + String 10 // name of parameter 5 + { + Text [ en-US ] = "barrier_low"; + }; + String 11 // description of parameter 5 + { + Text [ en-US ] = "lower barrier (set to 0 for no lower barrier)"; + }; + + String 12 // name of parameter 6 + { + Text [ en-US ] = "barrier_up"; + }; + String 13 // description of parameter 6 + { + Text [ en-US ] = "upper barrier (set to 0 for no upper barrier)"; + }; + }; + + + Resource PRICING_FUNCDESC_Opt_prob_inmoney + { + String 1 // description + { + Text [ en-US ] = "probability that an asset will at maturity end up between two barrier levels, assuming it follows dS/S = mu dt + vol dW (if the last two optional parameters (strike, put/call) are specified, the probability of S_T in [strike, upper barrier] for a call and S_T in [lower barrier, strike] for a put will be returned)"; + }; + + String 2 // name of parameter 1 + { + Text [ en-US ] = "spot"; + }; + String 3 // description of parameter 1 + { + Text [ en-US ] = "price/value of the asset"; + }; + + String 4 // name of parameter 2 + { + Text [ en-US ] = "vol"; + }; + String 5 // description of parameter 2 + { + Text [ en-US ] = "annual volatility of the asset"; + }; + + String 6 // name of parameter 3 + { + Text [ en-US ] = "drift"; + }; + String 7 // description of parameter 3 + { + Text [ en-US ] = "parameter mu from dS/S = mu dt + vol dW"; + }; + + String 8 // name of parameter 4 + { + Text [ en-US ] = "T"; + }; + String 9 // description of parameter 4 + { + Text [ en-US ] = "time to maturity in years"; + }; + + String 10 // name of parameter 5 + { + Text [ en-US ] = "barrier_low"; + }; + String 11 // description of parameter 5 + { + Text [ en-US ] = "lower barrier (set to 0 for no lower barrier)"; + }; + + String 12 // name of parameter 6 + { + Text [ en-US ] = "barrier_up"; + }; + String 13 // description of parameter 6 + { + Text [ en-US ] = "upper barrier (set to 0 for no upper barrier)"; + }; + + String 14 // name of parameter 7 + { + Text [ en-US ] = "put/call"; + }; + String 15 // description of parameter 7 + { + Text [ en-US ] = "optional (p)ut/(c)all indicator"; + }; + + String 16 // name of parameter 8 + { + Text [ en-US ] = "strike"; + }; + String 17 // description of parameter 8 + { + Text [ en-US ] = "optional strike level"; + }; + }; + + + + +}; + + +// function names as accessible from cells +Resource RID_PRICING_FUNCTION_NAMES +{ + String PRICING_FUNCNAME_Opt_barrier + { + Text [ en-US ] = "OPT_BARRIER"; + }; + String PRICING_FUNCNAME_Opt_touch + { + Text [ en-US ] = "OPT_TOUCH"; + }; + String PRICING_FUNCNAME_Opt_prob_hit + { + Text [ en-US ] = "OPT_PROB_HIT"; + }; + String PRICING_FUNCNAME_Opt_prob_inmoney + { + Text [ en-US ] = "OPT_PROB_INMONEY"; + }; + +}; + +// for translating function names +Resource RID_PRICING_DEFFUNCTION_NAMES +{ + +}; |