首页 > > 详细

FE5226程序辅导、c++编程语言辅导

Foundations of a Risk Management System
FE5226 Group Project
Fabio Cannizzo
version: 2021-08-28
Abstract
This source code constitutes the foundation of a risk management system. It can load trades from a database,
compute the price of trades and their sensitivities with respect to risk factors and construct market objects on demand.
A real risk management system entails of many more features, e.g. sophisticate market objects and pricing models;
efficient algorithms to avoid unnecessary recomputations when calculating Greeks; support for a large number of trade
types; extensive set of tools to orchestrate recomputations and post-process their results (e.g. P&L explain, VaR,
PFE, XVA); tools to manage life-cycle of trades; connections to external databases and systems of various nature;
client-server pricing APIs; connections to cash flow management systems and payment systems; support for parallel
computations (thread safety).
All these features can be implemented as modifications or extensions of the code provided. You are supposed to
carry out various improvements and extensions as specified below.
1 License
The license for the source code is in the main directory. Please read the license file.
2 Source code organization and build instructions
All source code files are in the subdirectory src. Source files with names matching the patterns Demo*.cpp or Test*.cpp
contain the main routine for separate programs. The other cpp files are library components used by the various
programs.
The target platform is x86 64 (64 bits). The C++ language standard used is: C++17. In Visual Studio you must:
• Select platform ”x64” (the default is ”x86”, i.e. 32 bits).
• Go to the property page for the project (right click on the project from solution explorer), select ”all platform”
and ”all configurations”, then navigate the configuration tree to C++/AllOptions and set:
– C++ language standard: C++17
– Disable language extensions: yes
– Treat all errors as warnings: yes
– Warning level: W3
The src subdirectory also contains a Makefile for gcc compilation. If you use Visual Studio, you need to: create a new
solution; in the solution add one console project for each cpp file with name Demo*.cpp or Test*.cpp; in each project
also add all other cpp files (except the ones with name Demo*.cpp or Test*.cpp), so that in each project you have one
and only one cpp file containing the function main. You can work in ”Debug” mode, which allows you to execute code
step by step and use breakpoints, but when you are finished with development and want to test the performance of your
final program you should use ”Release” mode. The language standard can be selected from the project configuration
(right click on the project in the Solution Explorer pane, then select C++/Lanugage/C++LanguageStandards). Note
that this must be repeated for all modes (debug and release).
A number of txt files are given. portfolio 0.txt and risk factors 0.txt work with the program in its current state.
portfolio i.txt and risk factors i.txt work after completion of the first i tasks. If a file with appropriate enumeration is
missing, you can use the last one available (e.g. in task 11, you can use risk factors 5.txt)
To run the program type from the command line:
DemoRisk -p portfolio.txt -f risk factors.txt
To run the program directly from inside Visual Studio, you can specify the working directory where your txt files
are located and the command line arguments (portfolio.txt risk factors.txt) in the Debugging section of the project
configuration.
1
3 What to do
You have to complete sequentially all tasks mentioned in section 6. After completing each task you should test
correctness of your work by succesfully running the command
DemoRisk portfolio i.txt risk factors i.txt
and comparing the output of your program with the output given in output i.txt. To compare files you can use the free
Windows program WinMerge, or sdiff on Linux. Your goal is to generate an output file identical to the one provided.
4 Marking criteria
Marking is going to be based on the following criteria.
4.1 Correctly follow submission instructions (-2 marks)
By simply following correctly submission procedures described in section 5, you get full marks. Otherwise, up to 2
marks are subtracted from your total mark. While this seems trivial, every year some student group fails to do this, so
please be careful.
4.2 Coding style (3 marks)
Follow good practice
• correct use of indentation (configure your editor to convert tab to spaces and to use tabs of 4 characters)
• if called with no arguments or with incorrect arguments, the program must produce an explanation of the correct
command line syntax required to invoke the program
• proper choices of variable and function names
• appropriate use of source code comments
• avoid code duplication (do not copy and paste, introduce new functions as appropriate)
• code robustness (e.g. assert function arguments are valid)
• code conciseness (do not do in 10 lines what you could do in one line)
• do not reinvent the wheel (use library functions when available)
• minimal changes to original files: only add or modify the lines of code strictly necessary, do not insert unnecessary
whitespaces (you can use WinMerge to view the difference between your files and the original ones, or use git,
which is excellent for checking differences). I will use WinMerge to check differences.
4.3 Date class correctness (2 marks)
I will look at you date class implementation and the test, focusing on correctness. I will run your date class against
my test.
4.4 Basic correctness (5 marks)
If your code compiles I will run your DemoRisk with the given trade portfolio and market data and compare your
output with mine using WinMerge. If there is a no difference, you get full marks. Note that if your code does not
compile, you will get zero marks. The command line help message should also be correct (include all accepted command
line arguments).
4.5 Performance (4 marks)
I create a very large test portfolio (millions of trades). As simple way to do this is to simply copy the given test set
portfolio many times in a bigger file. If your DemoRisk runs in a time comparable or better than my own implementation,
you get full marks. If section 4.4 fails, here you get zero marks. Common mistakes that can make your program slow are:
poor choice of data structures and redundant calculations (in particular, for market objects, do as much calculations
as possible when you construct the objects, and reuse this information when pricers query the market data objects).
4.6 Advanced correctness (4 marks)
I create an extended set of test test files, with more currencies and more special cases than what covered by the sample
test files. This may include expired trades (i.e. trades where the last payment date is before the pricing date, which
should generate an error), missing market data (e.g. a missing FX spot), missing fixings and other corner cases. If
your DemoRisk runs correctly reproducing the output file provided you get full marks. I will compare your output with
mine using WinMerge. If section 4.4 fails, here you get zero marks.
2
4.7 GCC build (3 marks)
Before submitting, verify that your program compiles and run also with the g++ compiler. To do that on Windows
64 bits you can:
• download setup-x86 64.exe from https://www.cygwin.com/install.html
• Run the installer. When you install, select at least the packages ”gcc-g++” and ”make”.
• launch cygwin and type the command cygpath -w $(pwd).
• Copy your cpp and h files and the Makefile I provided to the directory revealed by the previous command
• Type ”make”
• If all is well, you should see all your files compiling without errors and an executable file created.
• Test the executable file from the command line.
5 Submission instructions
• After completing all tasks you need to zip and submit all files with extension *.h and *.cpp.
• Do not submit any other file (e.g. txt files, visual studio project files, object files, executable files, output files).
• Files should be zipped without directory path. I.e. your zip file should contain file1.cpp, file2.cpp, ..., not
dirname\file1.cpp, dirname\file2.cpp, ....
• You need to include in the zip file also a file with name GROUP.TXT containing team members. The file must
contains the student IDs separated by a newline, i.e.
studentID1
studentID2
...
• Submit only a zip file, other formats are not allowed (e.g. arj, 7z)
• Submit only only once.
• Only one member of the team must submit, not all members.
6 Tasks
6.1 Improve the Date class
The most common operations performed with the Date class when pricing are comparison (e.g. <, ==, >) and
computation of distance between two dates. The current internal representation of the date class is not optimal for
these operations.
Refactor the Date class by modifying the current internal representation, which entails of the 4 data members day,
month, year and is leap, to a single data member of type unsigned with name serial, representing the number of days
elapsed since 1-Jan-1900. This allows to speed up the operations mentioned above and reduce memory footprint.
Change the serialization format to be based directly on serial, so that no extra work is necessary when saving or
loading from a file.
When the Date class is constructed from the arguments day, month and year, you need to generate the equivalent
serial number. When converting to a string in calendar format for display to the screen, you need to convert serial
on-the-fly into day, month and year.
6.2 Write a test for the Date class
Complete the program in TestDate.cpp, so that it tests the correctness of the Date class. It should perform the following
tests:
1. Construction of an invalid date should generate an error: generate intentionally 1000 random invalid dates (e.g.
31-Apr-2010) and verify that the Date class constructor throws an error (use try...catch).
2. Verify that converting a date in calendar format (day, month, year) to serial format and then converting back to
calendar format yields the original date. Repeat for all dates in the valid range (1-Jan-1900, 31-Dec-2199).
3. Verify that the serial number generated for 2 contiguous dates are contiguous. For instance 31-Jan-2012 and
1-Feb-2012 are contiguous dates, hence the serial numbers they generate should only differ by 1. Repeat for all
pairs of contiguous dates in the valid range (1-Jan-1900, 31-Dec-2199).
At the begin of the test, randomize the random number generator. If the test fails, the program should throw an
exception, if it succeeds it should just print the message ”SUCCESS”.
Print out the random seed you used for the random number generator, so that, if the test fails, a programmer can
re-use the same seed and reproduce the error, which is essential to be able to debug it.
3
6.3 Perfect streaming for type double
Currently when a floating point number in double precision is saved to a file it is transformed from IEEE-754 format
to a decimal representation with a finite number of decimals in scientific notation. The conversion from IEEE-754 to
decimal (when saving) and then back to IEEE-754 (when reading) involves rounding and can cause accuracy loss. In
other words, if we start from a value of type double, we save it as a string in decimal format, then we read back the
string and convert it to double, we may not get back exactly the same value we started with.
To overcome the problem, change the streaming representation of a double to the integer interpretation of its binary
representation in hexadecimal format with letters in lowercase.
If x is a variable of type double, it binary representation can be re-interpreted as a 64 bits integer, which can be
represented exactly. To do that, you can either get the memory address to the variable of type double and reinterpret cast
it to a 64-bit int pointer or use a union. To make the textual representation more compact, we use base 16 (hexadecimal).
For example, the double number -0.15625 should be saved to file as the sequence of 16 characters bfc4000000000000
(see example in DemoHex.cpp, which use a union). When reading, you need to read the integer number saved in
hexadecimal format and re-interpret it as a double.
You need to modify the implementation of the operator<< for double and implement the overload of the operator>>
(you may draw inspiration from the ones implemented for the Date class).
6.4 Improve the CurveDiscount class
The current CurveDiscount curve assumes that the interest rate curve is constant.
Modify it so that it takes a set of rates related to different tenors and modify it so that when querying for a discount
factor, the value returned is correctly interpolated.
For example, given the data points IR.1W.USD, IR.2W.USD, IR.1M.USD, IR.2M.USD, IR.3M.USD, IR.6M.USD,
IR.9M.USD, IR.1Y.USD, IR.18M.USD, IR.2Y.USD, ..., you need to resolve each of them to an actual date with respect
to the anchor date, construct a stepwise constant interpolation scheme, modify the function which returns discount
factor. For sake of clarity, D, W, M and Y mean respectively days, weeks, months and years. Although this is
not consistent with market conventions, for simplicity assumes that 1M=30 days and 1Y=365 days, and ignore the
distinction between weekdays and weekends when computing tenor dates.
Since you do not know in advance which points are available in the market data server, if you want all the available
points for the currency EUR, you need to modify the market data server to be able to return the array of risk factors
with pattern IR.*.EUR. Use the STL library to search for a string pattern and implement the method
MarketDataServer::matching, whose header is already defined in MarketDataServer.h. Note that ”IR.*.EUR” is not
the correct regular expression string to be used here, you need to read about regular expressions and figure out what
is the most appropriate string to use, i.e. it should match ”just” what needed. For instance, ”IR.*EUR” would match
”IR.1W.EUR”, but also ”IRwhateverEUR”, which is undesirable.
The interpolation scheme requires computation of the local rates. If ri and ri+1 are the absolute rates for tenor Ti
and Ti+1, as returned from the market data server, the local rate ri,i+1 is the one that solves the following equation:
e
−riTi−ri,i+1(Ti+1−Ti) = e
−ri+1Ti+1
Then the discount factor for any date t ∈ [Ti, Ti+1] is
df(t) = e
−riTi−ri,i+1(t−Ti)
In an efficient implementation as much calculation as possible should be done in the constructor, so that the function
df, which will be invoked millions of times, is as fast as possible. For instance, the values of the products riTi could be
precomputed for all i and cached in a data member of the class.
In the df function use binary search (see lower bound) to determine the interval i such that Ti ≤ t < Ti+1.
If the function df is called with a date beyond the last tenor or before the anchor date (today), it should generate
an error.
6.4.1 PV01 with tenors
The PV01 risk function needs to be modified into 2 different risk functions: PV01Parallel that computes risk with
respect to parallel shift of the yield curve (all risk factor move simultaneously); and PV01Bucketed that computes risk
with respect to individual yield curves (the yield curve for each tenor Ti change, with all the rest remaining constant).
In both cases use central differences, with the same bump size as currently defined in Demo.cpp. The 2 new functions
must have the same arguments and return type as the existing one.
6.5 Recover from pricing failures
The function IPricer::price fails and throws an exception when an error occurs. For instance, if the settlement date of
a Payment is in the past, pricing of the entire portfolio fails. We would like instead that only problematic trades fail
to price while all remaining trades price succesfully.
4
Modify the typedef portfolio values t to vector

联系我们
  • QQ:99515681
  • 邮箱:99515681@qq.com
  • 工作时间:8:00-21:00
  • 微信:codinghelp
热点标签

联系我们 - QQ: 99515681 微信:codinghelp
程序辅导网!