summaryrefslogtreecommitdiffstats
path: root/scaddins/source/pricing/pricing.cxx
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 05:54:39 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 05:54:39 +0000
commit267c6f2ac71f92999e969232431ba04678e7437e (patch)
tree358c9467650e1d0a1d7227a21dac2e3d08b622b2 /scaddins/source/pricing/pricing.cxx
parentInitial commit. (diff)
downloadlibreoffice-267c6f2ac71f92999e969232431ba04678e7437e.tar.xz
libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.zip
Adding upstream version 4:24.2.0.upstream/4%24.2.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'scaddins/source/pricing/pricing.cxx')
-rw-r--r--scaddins/source/pricing/pricing.cxx509
1 files changed, 509 insertions, 0 deletions
diff --git a/scaddins/source/pricing/pricing.cxx b/scaddins/source/pricing/pricing.cxx
new file mode 100644
index 0000000000..3182024abe
--- /dev/null
+++ b/scaddins/source/pricing/pricing.cxx
@@ -0,0 +1,509 @@
+/* -*- 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 <strings.hrc>
+
+#include <cppuhelper/factory.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/weak.hxx>
+#include <algorithm>
+#include <cmath>
+#include <string_view>
+#include <unotools/resmgr.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <o3tl/string_view.hxx>
+
+using namespace ::com::sun::star;
+using namespace sca::pricing;
+
+
+constexpr OUString ADDIN_SERVICE = u"com.sun.star.sheet.AddIn"_ustr;
+constexpr OUString MY_SERVICE = u"com.sun.star.sheet.addin.PricingFunctions"_ustr;
+constexpr OUStringLiteral MY_IMPLNAME = u"com.sun.star.sheet.addin.PricingFunctionsImpl";
+
+const ScaFuncDataBase pFuncDataArr[] =
+{
+ { "getOptBarrier", PRICING_FUNCNAME_OptBarrier, PRICING_FUNCDESC_OptBarrier, "OPT_BARRIER", 13, ScaCategory::Finance, false, false },
+ { "getOptTouch", PRICING_FUNCNAME_OptTouch, PRICING_FUNCDESC_OptTouch, "OPT_TOUCH", 11, ScaCategory::Finance, false, false },
+ { "getOptProbHit", PRICING_FUNCNAME_OptProbHit, PRICING_FUNCDESC_OptProbHit, "OPT_PROB_HIT", 6, ScaCategory::Finance, false, false },
+ { "getOptProbInMoney", PRICING_FUNCNAME_OptProbInMoney, PRICING_FUNCDESC_OptProbInMoney, "OPT_PROB_INMONEY", 8, ScaCategory::Finance, false, false },
+};
+
+ScaFuncData::ScaFuncData( const ScaFuncDataBase& rBaseData ) :
+ aIntName( OUString::createFromAscii( rBaseData.pIntName ) ),
+ pUINameID( rBaseData.pUINameID ),
+ pDescrID( rBaseData.pDescrID ),
+ nParamCount( rBaseData.nParamCount ),
+ eCat( rBaseData.eCat ),
+ bDouble( rBaseData.bDouble ),
+ bWithOpt( rBaseData.bWithOpt )
+{
+ aCompList.push_back(OUString::createFromAscii(rBaseData.pCompName));
+}
+
+sal_uInt16 ScaFuncData::GetStrIndex( sal_uInt16 nParam ) const
+{
+ if( !bWithOpt )
+ nParam++;
+ return (nParam > nParamCount) ? (nParamCount * 2) : (nParam * 2);
+}
+
+void sca::pricing::InitScaFuncDataList(ScaFuncDataList& rList)
+{
+ for (const auto & nIndex : pFuncDataArr)
+ rList.push_back(ScaFuncData(nIndex));
+}
+
+// entry points for service registration / instantiation
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+scaddins_ScaPricingAddIn_get_implementation(
+ css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new ScaPricingAddIn());
+}
+
+// "normal" service implementation
+ScaPricingAddIn::ScaPricingAddIn()
+{
+}
+
+ScaPricingAddIn::~ScaPricingAddIn()
+{
+}
+
+static const char* pLang[] = { "en" };
+static const char* pCoun[] = { "US" };
+const sal_uInt32 nNumOfLoc = SAL_N_ELEMENTS( pLang );
+
+void ScaPricingAddIn::InitDefLocales()
+{
+ pDefLocales.reset( 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 < nNumOfLoc) ? pDefLocales[ nIndex ] : aFuncLoc;
+}
+
+void ScaPricingAddIn::InitData()
+{
+ aResLocale = Translate::Create("sca", LanguageTag(aFuncLoc));
+ pFuncDataList.reset(new ScaFuncDataList);
+ InitScaFuncDataList(*pFuncDataList);
+ pDefLocales.reset();
+}
+
+OUString ScaPricingAddIn::GetFuncDescrStr(const TranslateId* pResId, sal_uInt16 nStrIndex)
+{
+ return ScaResId(pResId[nStrIndex - 1]);
+}
+
+// XServiceName
+OUString SAL_CALL ScaPricingAddIn::getServiceName()
+{
+ // name of specific AddIn service
+ return MY_SERVICE;
+}
+
+// XServiceInfo
+OUString SAL_CALL ScaPricingAddIn::getImplementationName()
+{
+ return MY_IMPLNAME;
+}
+
+sal_Bool SAL_CALL ScaPricingAddIn::supportsService( const OUString& aServiceName )
+{
+ return cppu::supportsService(this, aServiceName);
+}
+
+uno::Sequence< OUString > SAL_CALL ScaPricingAddIn::getSupportedServiceNames()
+{
+ return { ADDIN_SERVICE, MY_SERVICE };
+}
+
+// XLocalizable
+void SAL_CALL ScaPricingAddIn::setLocale( const lang::Locale& eLocale )
+{
+ aFuncLoc = eLocale;
+ InitData(); // change of locale invalidates resources!
+}
+
+lang::Locale SAL_CALL ScaPricingAddIn::getLocale()
+{
+ return aFuncLoc;
+}
+
+// function descriptions start here
+// XAddIn
+OUString SAL_CALL ScaPricingAddIn::getProgrammaticFuntionName( const OUString& )
+{
+ // 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 )
+{
+ OUString aRet;
+
+ auto fDataIt = std::find_if(pFuncDataList->begin(), pFuncDataList->end(),
+ FindScaFuncData( aProgrammaticName ) );
+ if (fDataIt != pFuncDataList->end() )
+ {
+ aRet = ScaResId(fDataIt->GetUINameID());
+ if( fDataIt->IsDouble() )
+ aRet += "_ADD";
+ }
+ else
+ {
+ aRet = "UNKNOWNFUNC_" + aProgrammaticName;
+ }
+
+ return aRet;
+}
+
+OUString SAL_CALL ScaPricingAddIn::getFunctionDescription( const OUString& aProgrammaticName )
+{
+ OUString aRet;
+
+ auto fDataIt = std::find_if( pFuncDataList->begin(), pFuncDataList->end(),
+ FindScaFuncData( aProgrammaticName ) );
+ if( fDataIt != pFuncDataList->end() )
+ aRet = GetFuncDescrStr( fDataIt->GetDescrID(), 1 );
+
+ return aRet;
+}
+
+OUString SAL_CALL ScaPricingAddIn::getDisplayArgumentName(
+ const OUString& aProgrammaticName, sal_Int32 nArgument )
+{
+ OUString aRet;
+
+ auto fDataIt = std::find_if( pFuncDataList->begin(), pFuncDataList->end(),
+ FindScaFuncData( aProgrammaticName ) );
+ if( fDataIt != pFuncDataList->end() && (nArgument <= 0xFFFF) )
+ {
+ sal_uInt16 nStr = fDataIt->GetStrIndex( static_cast< sal_uInt16 >( nArgument ) );
+ if( nStr )
+ aRet = GetFuncDescrStr( fDataIt->GetDescrID(), nStr );
+ else
+ aRet = "internal";
+ }
+
+ return aRet;
+}
+
+OUString SAL_CALL ScaPricingAddIn::getArgumentDescription(
+ const OUString& aProgrammaticName, sal_Int32 nArgument )
+{
+ OUString aRet;
+
+ auto fDataIt = std::find_if( pFuncDataList->begin(), pFuncDataList->end(),
+ FindScaFuncData( aProgrammaticName ) );
+ if( fDataIt != pFuncDataList->end() && (nArgument <= 0xFFFF) )
+ {
+ sal_uInt16 nStr = fDataIt->GetStrIndex( static_cast< sal_uInt16 >( nArgument ) );
+ if( nStr )
+ aRet = GetFuncDescrStr( fDataIt->GetDescrID(), nStr + 1 );
+ else
+ aRet = "for internal use only";
+ }
+
+ return aRet;
+}
+
+OUString SAL_CALL ScaPricingAddIn::getProgrammaticCategoryName(
+ const OUString& aProgrammaticName )
+{
+ OUString aRet;
+
+ auto fDataIt = std::find_if( pFuncDataList->begin(), pFuncDataList->end(),
+ FindScaFuncData( aProgrammaticName ) );
+ if( fDataIt != pFuncDataList->end() )
+ {
+ switch( fDataIt->GetCategory() )
+ {
+ case ScaCategory::DateTime: aRet = "Date&Time"; break;
+ case ScaCategory::Text: aRet = "Text"; break;
+ case ScaCategory::Finance: aRet = "Financial"; break;
+ case ScaCategory::Inf: aRet = "Information"; break;
+ case ScaCategory::Math: aRet = "Mathematical"; break;
+ case ScaCategory::Tech: aRet = "Technical"; break;
+ }
+ }
+
+ if( aRet.isEmpty() )
+ aRet = "Add-In";
+ return aRet;
+}
+
+OUString SAL_CALL ScaPricingAddIn::getDisplayCategoryName(
+ const OUString& aProgrammaticName )
+{
+ return getProgrammaticCategoryName( aProgrammaticName );
+}
+
+// XCompatibilityNames
+uno::Sequence< sheet::LocalizedName > SAL_CALL ScaPricingAddIn::getCompatibilityNames(
+ const OUString& aProgrammaticName )
+{
+ auto fDataIt = std::find_if( pFuncDataList->begin(), pFuncDataList->end(),
+ FindScaFuncData( aProgrammaticName ) );
+ if( fDataIt == pFuncDataList->end() )
+ return uno::Sequence< sheet::LocalizedName >( 0 );
+
+ const std::vector<OUString>& rStrList = fDataIt->GetCompNameList();
+ sal_uInt32 nCount = rStrList.size();
+
+ 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[nIndex] );
+
+ return aRet;
+}
+
+// actual function implementation starts here
+// auxiliary input handling functions
+namespace {
+
+bool getinput_putcall(bs::types::PutCall& pc, std::u16string_view str) {
+ if(o3tl::starts_with(str, u"c")) {
+ pc=bs::types::Call;
+ } else if(o3tl::starts_with(str, u"p")) {
+ pc=bs::types::Put;
+ } else {
+ return false;
+ }
+ return true;
+}
+
+bool getinput_putcall(bs::types::PutCall& pc, const uno::Any& anyval) {
+ OUString str;
+ if(anyval.getValueTypeClass() == uno::TypeClass_STRING) {
+ anyval >>= str;
+ } else if(anyval.getValueTypeClass() == uno::TypeClass_VOID) {
+ str="c"; // call as default
+ } else {
+ return false;
+ }
+ return getinput_putcall(pc, str);
+}
+
+bool getinput_strike(double& strike, const uno::Any& anyval) {
+ if(anyval.getValueTypeClass() == uno::TypeClass_DOUBLE) {
+ anyval >>= strike;
+ } else if(anyval.getValueTypeClass() == uno::TypeClass_VOID) {
+ strike=-1.0; // -1 as default (means not set)
+ } else {
+ return false;
+ }
+ return true;
+}
+
+bool getinput_inout(bs::types::BarrierKIO& kio, std::u16string_view str) {
+ if(o3tl::starts_with(str, u"i")) {
+ kio=bs::types::KnockIn;
+ } else if(o3tl::starts_with(str, u"o")) {
+ kio=bs::types::KnockOut;
+ } else {
+ return false;
+ }
+ return true;
+}
+
+bool getinput_barrier(bs::types::BarrierActive& cont, std::u16string_view str) {
+ if(o3tl::starts_with(str, u"c")) {
+ cont=bs::types::Continuous;
+ } else if(o3tl::starts_with(str, u"e")) {
+ cont=bs::types::Maturity;
+ } else {
+ return false;
+ }
+ return true;
+}
+
+bool getinput_fordom(bs::types::ForDom& fd, std::u16string_view str) {
+ if(o3tl::starts_with(str, u"f")) {
+ fd=bs::types::Foreign;
+ } else if(o3tl::starts_with(str, u"d")) {
+ fd=bs::types::Domestic;
+ } else {
+ return false;
+ }
+ return true;
+}
+
+bool getinput_greek(bs::types::Greeks& greek, const uno::Any& anyval) {
+ OUString str;
+ if(anyval.getValueTypeClass() == uno::TypeClass_STRING) {
+ anyval >>= str;
+ } else if(anyval.getValueTypeClass() == uno::TypeClass_VOID) {
+ str="value";
+ } else {
+ return false;
+ }
+
+ if(str == "value" || str == "price" || str == "v" || str == "p") {
+ greek=bs::types::Value;
+ } else if(str == "delta" || str == "d") {
+ greek=bs::types::Delta;
+ } else if(str == "gamma" || str == "g") {
+ greek=bs::types::Gamma;
+ } else if(str == "theta" || str == "t") {
+ greek=bs::types::Theta;
+ } else if(str == "vega" || str == "e") {
+ greek=bs::types::Vega;
+ } else if(str == "volga" || str == "o") {
+ greek=bs::types::Volga;
+ } else if(str == "vanna" || str == "a") {
+ greek=bs::types::Vanna;
+ } else if(str == "rho" || str == "r") {
+ greek=bs::types::Rho_d;
+ } else if(str == "rhof" || str == "f") {
+ greek=bs::types::Rho_f;
+ } else {
+ return false;
+ }
+ return true;
+}
+
+} // namespace for auxiliary functions
+
+// OPT_BARRIER(...)
+double SAL_CALL ScaPricingAddIn::getOptBarrier( double spot, double vol,
+ double r, double rf, double T, double strike,
+ double barrier_low, double barrier_up, double rebate,
+ const OUString& put_call, const OUString& in_out,
+ const OUString& barriercont, const uno::Any& greekstr )
+{
+ 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 lang::IllegalArgumentException();
+ }
+
+ double fRet=bs::barrier(spot,vol,r,rf,T,strike, barrier_low,barrier_up,
+ rebate,pc,kio,bcont,greek);
+
+ if (!std::isfinite(fRet))
+ throw css::lang::IllegalArgumentException();
+ return fRet;
+}
+
+// OPT_TOUCH(...)
+double SAL_CALL ScaPricingAddIn::getOptTouch( double spot, double vol,
+ double r, double rf, double T,
+ double barrier_low, double barrier_up,
+ const OUString& for_dom, const OUString& in_out,
+ const OUString& barriercont, const uno::Any& greekstr )
+{
+ 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 lang::IllegalArgumentException();
+ }
+
+ double fRet=bs::touch(spot,vol,r,rf,T,barrier_low,barrier_up,
+ fd,kio,bcont,greek);
+
+ if (!std::isfinite(fRet))
+ throw css::lang::IllegalArgumentException();
+ return fRet;
+}
+
+// OPT_PRB_HIT(...)
+double SAL_CALL ScaPricingAddIn::getOptProbHit( double spot, double vol,
+ double mu, double T,
+ double barrier_low, double barrier_up )
+{
+ // read and check input values
+ if( spot<=0.0 || vol<=0.0 || T<0.0 ) {
+ throw lang::IllegalArgumentException();
+ }
+
+ double fRet=bs::prob_hit(spot,vol,mu,T,barrier_low,barrier_up);
+
+ if (!std::isfinite(fRet))
+ throw css::lang::IllegalArgumentException();
+ return fRet;
+}
+
+// OPT_PROB_INMONEY(...)
+double SAL_CALL ScaPricingAddIn::getOptProbInMoney( double spot, double vol,
+ double mu, double T,
+ double barrier_low, double barrier_up,
+ const uno::Any& strikeval, const uno::Any& put_call )
+{
+ bs::types::PutCall pc=bs::types::Call;
+ double K = 0;
+
+ // 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 lang::IllegalArgumentException();
+ }
+
+ double fRet=bs::prob_in_money(spot,vol,mu,T,K,barrier_low,barrier_up,pc);
+
+ if (!std::isfinite(fRet))
+ throw css::lang::IllegalArgumentException();
+ return fRet;
+}
+
+OUString ScaPricingAddIn::ScaResId(TranslateId aResId)
+{
+ return Translate::get(aResId, aResLocale);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */