Monday, December 26, 2016

XLW : Interfacing C++11 PathGenerator to Excel

In my previous post on generating paths for different types of one-factor processes, I was writing all processed paths sequentially into separate CSV files. Later, these files could be opened in Excel for any further use. This approach is far from being an efficient way to interface C++ program to Excel. While being possible to create in-house tool for this task, the actual implementation part requires relatively deep understanding and hands-on experience on Excel/C API. The amount of issues to be learned in order to produce truly generic and reliable tool, is far from being something which could be internalized in very short period of time. There are limited amount of books available on this topic, but the most recommended book is the one written by Steve Dalton.

This time, I wanted to present kind of "industry standard" way to accomplish this task using "easy-to-use" Excel/C++ interfacing tool, which has been there already since 2002. XLW is an application which wraps Excel/C API into a simple C++ interface, which can then be used to customize Excel with user-defined worksheet functions. For any newcomer into this issue, it is highly recommended first to watch instructional "how-to-use" clips from project homepage. The complete workflow of using XLW wrapper is presented there from downloading to debugging. Also, AdaptiveRisk blog is presenting extremely useful stuff, well enough to get started.


cppinterface.h


For this project, I have extracted a new XLW xll template and opened corresponding solution in my Visual Studio Express 2013. The content of this header file in my current project is presented below. I have method declarations for two functions, which are both returning matrix object (XLW data structure). It is my intention to use my previous PathGenerator project, in order to fill these matrix objects with paths using desired one-factor processes.

#ifndef TEST_H
#define TEST_H
//
#include "xlw/MyContainers.h"
#include <xlw/CellMatrix.h>
#include <xlw/DoubleOrNothing.h>
#include <xlw/ArgList.h>
#include <xlw/XlfServices.h>
//
using namespace xlw;
//
//<xlw:libraryname=XLWPathGenerator
//
// method for requesting vasicek paths
MyMatrix // return matrix of random paths following Vasicek SDE
//<xlw:volatile
GetPaths_Vasicek(double t, // time to maturity
double r, // current short rate
double longTermRate, // long-term average rate
double meanReversion, // mean reversion speed
double rateVolatility // rate volatility
);
//
// method for requesting GBM paths
MyMatrix // return matrix of random paths following Geometric Brownian Motion SDE
//<xlw:volatile
GetPaths_BrownianMotion(double t, // time to maturity
double s, // current spot rate
double rate, // risk-free rate
double volatility // volatility
);
//
#endif

Commenting may seem a bit strange first, but the following screenshot containing Excel function argument input box may help to catch the point.















source.cpp


Implementations for two methods declared in header file are presented below. Information concerning number of time steps (for a path) and number of paths to be created are extracted from matrix dimensions using XlfServices object. After this, desired OneFactorProcess and PathGenerator objects are created. Finally, PathGenerator object is used to process a path, which will be imported into resulting matrix object (paths) and returned for the client (Excel).

#include <cppinterface.h>
#include "PathGenerator.h"
#pragma warning (disable : 4996)
//
MyMatrix GetPaths_Vasicek(double t, double r, double longTermRate, double meanReversion, double rateVolatility)
{
 // request dimensions for calling matrix
 const unsigned int nPaths = XlfServices.Information.GetCallingCell().columns();
 const unsigned int nSteps = XlfServices.Information.GetCallingCell().rows();
 // create container for all processed paths
 MyMatrix paths(nSteps, nPaths);
 // create container for a single path to be processed
 MyArray path(nSteps);
 //
 // create vasicek process and path generator
 std::shared_ptr<MJProcess::OneFactorProcess> vasicek =
  std::shared_ptr<MJProcess::Vasicek>(new MJProcess::Vasicek(meanReversion, longTermRate, rateVolatility));
 PathGenerator<> shortRateProcess(r, t, vasicek);
 //
 // process paths using path generator
 for (unsigned int i = 0; i != nPaths; ++i)
 {
  shortRateProcess(path);
  // import processed path into paths container
  for (unsigned j = 0; j != nSteps; ++j)
  {
   paths[j][i] = path[j];
  }
 }
 return paths;
}
//
MyMatrix GetPaths_BrownianMotion(double t, double s, double rate, double volatility)
{
 // request dimensions for calling matrix
 const unsigned int nPaths = XlfServices.Information.GetCallingCell().columns();
 const unsigned int nSteps = XlfServices.Information.GetCallingCell().rows();
 // create container for all processed paths
 MyMatrix paths(nSteps, nPaths);
 // create container for a single path to be processed
 MyArray path(nSteps);
 //
 // create geometric brownian motion process and path generator
 std::shared_ptr<MJProcess::OneFactorProcess> brownianMotion =
  std::shared_ptr<MJProcess::GBM>(new MJProcess::GBM(rate, volatility));
 PathGenerator<> equityPriceProcess(s, t, brownianMotion);
 //
 // process paths using path generator
 for (unsigned int i = 0; i != nPaths; ++i)
 {
  equityPriceProcess(path);
  // import processed path into paths container
  for (unsigned j = 0; j != nSteps; ++j)
  {
   paths[j][i] = path[j];
  }
 }
 return paths;
}
//


In order to get this thing up and running, header file for PathGenerator has to be included. I have set the current XLL project as startup project. As a side, I have opened my PathGenerator project (containing header files for RandomGenerator, OneFactorProcess and PathGenerator). Since this side project is still unaccessible, it has to be linked to my current XLL project : Project - Properties - Configuration Properties - C/C++ - General - Additional Include Directories (Browse folder containing source files for the project to be linked). After completing these steps and building this project succesfully, I am finally ready to test the provided functionality in Excel.


Excel


After opening a new Excel, I need to drag-and-drop (or open from Excel) newly created xll template from my \\Projects\XLWTester\Debug folder to Excel. In my Excel (screenshot below), I have two boxes for input parameters (Vasicek, Brownian Motion) and two ranges for resulting one-factor process paths (36 steps, 15 paths). As soon as I hit F9 button, my one-factor paths will be re-created. Finally, it should be noted that the functions are both array formulas.





















Finally, thanks for reading this blog. Pleasant waiting for a new year for everybody.
-Mike

Sunday, December 18, 2016

C++11 : PathGenerator Class

This blog posting is a sequel for the post I published just a couple of days ago. Having tools for generating random numbers is nice, but I still wanted to put that Random Generator template class to do something even more useful, like to produce paths for asset prices.

The idea was to create some practical means for transforming random number paths into asset price paths, following any desired (one-factor) stochastic process. For this purpose, I have created one template class (PathGenerator), which is technically just a wrapper for RandomGenerator template class and OneFactorProcess polymorphic class hierarchy. The purpose of RandomGenerator is to produce random numbers from desired probability distribution (usually that is standard normal) and the purpose of OneFactorProcess implementation is to provide information for PathGenerator on how to calculate drift and diffusion coefficients for a chosen stochastic process.


PATHS


For a marketing reasons, let us see the end product first. Simulated asset price paths for Geometric Brownian Motion and Vasicek processes are presented in Excel screenshot below. Test program (presented below) has been created in a way, that all processed asset price paths for a chosen stochastic process are exported into CSV file (which can then be imported into Excel for further investigation).

















ONE-FACTOR PROCESS


Abstract base class (OneFactorProcess) is technically just an interface, which provides practical means for a client for customizing drift and diffusion functions for different types of stochastic processes. I decided to implement polymorphic class hierarchy, since class is still pretty compact place for storing private member data and corresponding algorithms using that member data.

In the first draft, I was actually implementing drift and diffusion coefficient algorithms by using functions and lambdas, which (being initially created in main program) would then have been used inside PathGenerator object. It was technically working well, but from the viewpoint of possible end user (say, having member data and algorithm implementations in different files) it would have been quite a different story.

#pragma once
//
namespace MikeJuniperhillOneFactorProcessLibrary
{
 /// <summary>
 /// Abstract base class for all one-factor processes
 /// is technically just an interface, which provides practical means
 /// for customizing drift and diffusion functions for different types of processes.
 /// </summary>
 class OneFactorProcess
 {
 public:
  virtual double drift(double x, double t) = 0;
  virtual double diffusion(double x, double t) = 0;
 };
 //
 /// <summary>
 /// Implementation for Vasicek short-rate model.
 /// </summary>
 class Vasicek : public OneFactorProcess
 {
 public:
  Vasicek(double meanReversion, double longTermRate, double rateVolatility)
   : meanReversion(meanReversion), longTermRate(longTermRate), rateVolatility(rateVolatility) { }
  double drift(double x, double t) override { return meanReversion * (longTermRate - x); }
  double diffusion(double x, double t) override { return rateVolatility; }
 private:
  double meanReversion;
  double longTermRate;
  double rateVolatility;
 };
 //
 /// <summary>
 /// Implementation for Geometric Brownian Motion.
 /// </summary>
 class GBM : public OneFactorProcess
 {
 public:
  GBM(double rate, double volatility) : rate(rate), volatility(volatility) { }
  double drift(double x, double t) override { return rate * x; }
  double diffusion(double x, double t) override { return x * volatility; }
 private:
  double rate;
  double volatility;
 };
}


PATH GENERATOR


PathGenerator object is using RandomGenerator object for creating random numbers from standard normal probability distribution, by using default seeder for default uniform generator (Mersenne Twister). At some point, this class was having several different constructors for client-given seeder and client-given probability distribution. However, for the sake of clarity, I decided to remove all that optionality. In most of the cases, we want to simulate random numbers from standard normal distribution and Mersenne Twister generator still does the uniform part pretty well. It should be noted, that if such a customizing need sometimes arises, this class can be modified accordingly.

#pragma once
//
#include "RandomGenerator.h"
#include "OneFactorProcess.h"
namespace MJRandom = MikeJuniperhillRandomGeneratorTemplate;
namespace MJProcess = MikeJuniperhillOneFactorProcessLibrary;
//
template <typename Generator = std::mt19937, typename Distribution = std::normal_distribution<double>>
class PathGenerator
{
public:
 /// <summary>
 /// Constructor for PathGenerator template class.
 /// <para> - using default seeder from chrono library </para>
 /// <para> - using standard normal distribution </para>
 /// <para> - using mersenne twister uniform generator </para>
 /// </summary>
 PathGenerator(double spot, double maturity, std::shared_ptr<MJProcess::OneFactorProcess>& process)
  : spot(spot), maturity(maturity), process(process)
 {
  // create default seeder lambda function for random generator
   this->seeder = [](void) -> unsigned long { return static_cast<unsigned long>
    (std::chrono::steady_clock::now().time_since_epoch().count()); };
  // create random generator
  generator = std::unique_ptr<MJRandom::RandomGenerator<Generator, Distribution>>
   (new MJRandom::RandomGenerator<Generator, Distribution>(this->seeder));
 }
 /// <summary> 
 /// Functor, which fills auxiliary vector reference with asset prices following a given stochastic process.
 /// </summary>  
 void operator()(std::vector<double>& v)
 {
  // transform initialized vector into a path containing random numbers
  (*generator)(v);
  //
  double dt = maturity / (v.size() - 1);
  double dw = 0.0;
  double s = spot;
  double t = 0.0;
  v[0] = s; // 1st path element is always the current spot price
  //
  // transform random number vector into a path containing asset prices
  for (auto it = v.begin() + 1; it != v.end(); ++it)
  {
   t += dt;
   dw = (*it) * std::sqrt(dt);
   (*it) = s + (*process).drift(s, t) * dt + (*process).diffusion(s, t) * dw;
   s = (*it);
  }
 }
private:
 double spot;
 double maturity;
 std::function<unsigned long(void)> seeder;
 std::shared_ptr<MJProcess::OneFactorProcess> process;
 std::unique_ptr<MJRandom::RandomGenerator<Generator, Distribution>> generator;
};


TESTER


Presented test program is creating two different one-factor processes (Geometric Brownian Motion, Vasicek) and using PathGenerator for simulating asset price paths. All processed paths for the both cases will then be printed into CSV file for further investigations (Excel). I dare to say, that the process of generating asset price paths for one-factor process is easy and straightforward with PathGenerator class. For testing purposes, RandomGenerator header file should be included in the project.

#include "PathGenerator.h"
#include <fstream>
//
// printer : after a simulation iteration, append a path content into a file
// this inefficient idiom is not suitable for anything else but crude testing
void Print(const std::vector<double>& v, const std::string& filePathName)
{
 std::ofstream file(filePathName, std::ios_base::app);
 for (auto& element : v) { file << std::to_string(element) << ";"; }
 file << std::endl;
}
//
int main()
{
 // define and delete output CSV test files
 const std::string fileForVasicekProcess = "C:\\temp\\paths.vasicek.csv";
 const std::string fileForBrownianMotion = "C:\\temp\\paths.brownianMotion.csv";
 std::remove(fileForVasicekProcess.c_str());
 std::remove(fileForBrownianMotion.c_str());
 //
 // create auxiliary vector container for path processing
 double t = 3.0; // time to maturity
 int nPaths = 250; // number of simulated paths
 int nSteps = 1095; // number of time steps in one path (3 years * 365 days = 1095 steps)
 // the size of vector must be the number of desired time steps 
 // plus one, since the first vector item will be the current asset spot price
 std::vector<double> path(nSteps + 1);
 //
 // example 1 : create paths using vasicek process
 double r = 0.0095;
 double longTermRate = 0.05;
 double meanReversion = 0.2;
 double rateVolatility = 0.0075;
 std::shared_ptr<MJProcess::OneFactorProcess> vasicek =
  std::shared_ptr<MJProcess::Vasicek>(new MJProcess::Vasicek(meanReversion, longTermRate, rateVolatility));
 PathGenerator<> shortRateProcess(r, t, vasicek);
 for (int i = 0; i != nPaths; ++i)
 {
  shortRateProcess(path); // generate a path
  Print(path, fileForVasicekProcess); // print a path
 }
 //
 // example 2 : create paths using geometric brownian process
 double s = 100.0;
 double rate = 0.02;
 double volatility = 0.25;
 std::shared_ptr<MJProcess::OneFactorProcess> brownianMotion =
  std::shared_ptr<MJProcess::GBM>(new MJProcess::GBM(rate, volatility));
 PathGenerator<> equityPriceProcess(s, t, brownianMotion);
 for (int i = 0; i != nPaths; ++i)
 {
  equityPriceProcess(path);  // generate a path
  Print(path, fileForBrownianMotion); // print a path
 }
 return 0;
}

Finally, thanks for reading my blog and have a very pleasant waiting time for Christmas.
-Mike



Thursday, December 15, 2016

C++11 : Template Class for Random Generator

"Anyone who attempts to generate random numbers by deterministic means is, 
of course, living in a state of sin." - John Von Neumann

Despite of the fact that the quote above is still highly relevant, we mostly get the job done well enough using those pseudo-random generators for our Monte Carlo stuff. So, this time I wanted to present a wrapper for simulating (sinful) uniform random numbers, which are then mapped to a chosen probability distribution. The main goal was to construct a lightweight design, using C++11 uniform generators, probability distributions as well as some other extremely useful tools (function, lambda) for the task.


TEMPLATE DIET


Instead of implementing any class hierarchies, I tried to keep this design as lightweighted as possible by using template class having only two template data types to be defined by a client : Generator (uniform random generator) and Distribution (probability distribution for transforming uniformly distributed random numbers). In a nutshell, a client may use any random number engine available in C++11, for creating desired amount of uniform random numbers. Moreover, a client may use default probability distribution (Standard Normal) for transforming created uniform random numbers or additionally, use any desired probability distribution available in C++11. Available uniform random engines and probability distributions have been nicely covered in here.


ULTIMATE SIN


It should be a bit easier to sell something, if the final product is nicely presented. Random numbers processed by example program (presented later) for four different random generator implementations are presented in Excel screenshot below.




















HEADER FILE


Random generator template class is presented below. Note, that this implementation does not require any auxiliary libraries, since all the required stuff is already in C++11. For usability reasons, I decided to keep all the actual method implementations in header file (RandomGenerator.h).

#pragma once
#include <algorithm>
#include <chrono>
#include <cmath>
#include <functional>
#include <iostream>
#include <math.h>
#include <memory>
#include <random>
#include <string>
#include <vector>
//
namespace MikeJuniperhillRandomGeneratorTemplate
{
 template <typename Generator = std::mt19937, typename Distribution = std::normal_distribution<double>>
 /// <summary> 
 /// Template class for creating random number paths using
 /// Mersenne Twister as default uniform random generator and 
 /// Standard Normal (0.0, 1.0) as default probability distribution.
 /// </summary>  
 class RandomGenerator
 {
 public:
  /// <summary>
  /// Constructor for using default probability distribution 
  /// for transforming uniform random numbers.
  /// </summary>  
  RandomGenerator(const std::function<unsigned long(void)>& seeder)
   : seeder(seeder)
  {
   // construct lambda method for processing standard normal random number
   randomGenerator = [this](double x)-> double
   {
    x = distribution(uniformGenerator);
    return x;
   };
   // seed uniform random generator with a client-given algorithm
   uniformGenerator.seed(seeder());
  }
  /// <summary> 
  /// Constructor for using client-given probability distribution 
  /// for transforming uniform random numbers.
  /// </summary>  
  RandomGenerator(const std::function<unsigned long(void)>& seeder, const Distribution& distribution)
   // constructor delegation for initializing other required member data
   : RandomGenerator(seeder)
  {
   // assign client-given probability distribution
   this->distribution = distribution;
  }
  /// <summary> 
  /// Functor filling vector with random numbers mapped to chosen probability distribution.
  /// </summary>  
  void operator()(std::vector<double>& v)
  {
   std::transform(v.begin(), v.end(), v.begin(), randomGenerator);
  }
 private:
  std::function<unsigned long(void)> seeder;
  std::function<double(double)> randomGenerator;
  Generator uniformGenerator;
  Distribution distribution;
 };
}


TESTER FILE


Example program (tester.cpp) for testing random generator functionality is presented below. The process of generating (pseudo) random numbers from a probability distribution is easy and straightforward with this template wrapper class.

#include "RandomGenerator.h"
namespace MJ = MikeJuniperhillRandomGeneratorTemplate;
//
// printer for a random path
void Print(const std::string& message, const std::vector<double>& v)
{
 std::cout << message << std::endl;
 for (auto& element : v) std::cout << element << std::endl;
 std::cout << std::endl;
}
//
int main()
{
 // construct lambda method for seeding uniform random generator
 std::function<unsigned long(void)> seeder = 
  [](void) -> unsigned long { return static_cast<unsigned long>
  (std::chrono::steady_clock::now().time_since_epoch().count()); };
 //
 // create vector for a path to be filled with 20 random numbers
 // from desired probability distribution, using desired uniform random generator
 int nSteps = 20;
 std::vector<double> path(nSteps);
 //
 // path generator : mersenne twister, standard normal
 MJ::RandomGenerator<> gen_1(seeder);
 gen_1(path);
 Print("mt19937 : x~N(0.0, 1.0)", path);
 //
 // path generator : minst_rand, standard normal
 MJ::RandomGenerator<std::minstd_rand> gen_2(seeder);
 gen_2(path);
 Print("minstd_rand : x~N(0.0, 1.0)", path);
 //
 // path generator : mersenne twister, normal(112.5, 1984.0)
 std::normal_distribution<double> nd(112.5, 1984.0);
 MJ::RandomGenerator<> gen_3(seeder, nd);
 gen_3(path);
 Print("mt19937 : x~N(112.5, 1984.0)", path);
 //
 // path generator : minstd_rand, exponential(3.14)
 std::exponential_distribution<double> ed(3.14);
 MJ::RandomGenerator<std::minstd_rand, std::exponential_distribution<double>> gen_4(seeder, ed);
 gen_4(path);
 Print("minstd_rand : x~Exp(3.14)", path);
 //
 return 0;
}

Finally, thanks again for reading this blog.
-Mike