Skip to content

Commit 86380bd

Browse files
authored
Merge pull request #1243 from cppalliance/1213
Improvements to financial examples page
2 parents c795e7e + e23a669 commit 86380bd

File tree

7 files changed

+187
-178
lines changed

7 files changed

+187
-178
lines changed

doc/modules/ROOT/pages/examples.adoc

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,12 @@ https://www.boost.org/LICENSE_1_0.txt
88
= Examples
99
:idprefix: examples_
1010

11-
All examples can be found in the library `examples/` folder as well.
11+
The following examples will help you get up and running with many of the major parts of the library.
12+
All of these examples can be found in the library `examples/` folder as well.
1213

1314
[#examples_construction]
1415
== Basic Construction
15-
.This example demonstrates the basic use of the various constructors offered by the decimal types
16+
.This https://github.com/cppalliance/decimal/blob/develop/examples/basic_construction.cpp[example] demonstrates the basic use of the various constructors offered by the decimal types
1617
====
1718
[source, c++]
1819
----
@@ -35,7 +36,7 @@ Can not construct from invalid string
3536
[#examples_promotion]
3637
== Promotion and Mixed Decimal Arithmetic
3738
38-
.This example demonstrates the behaviors of promotion between types, and mixed decimal type arithmetic
39+
.This https://github.com/cppalliance/decimal/blob/develop/examples/promotion.cpp[example] demonstrates the behaviors of promotion between types, and mixed decimal type arithmetic
3940
====
4041
[source, c++]
4142
----
@@ -56,7 +57,7 @@ The result of a + b is a decimal64_t: 9.1
5657
[#examples_charconv]
5758
== `<charconv>`
5859
59-
.This example demonstrates the fundamentals of the `<charconv>` like functions provided by the library
60+
.This https://github.com/cppalliance/decimal/blob/develop/examples/charconv.cpp[example] demonstrates the fundamentals of the `<charconv>` like functions provided by the library
6061
====
6162
[source, c++]
6263
----
@@ -74,7 +75,7 @@ Value in scientific format with precision 20: -7.12345000000000000000e+06
7475
7576
[#examples_generic_programming]
7677
== Generic Programming
77-
.This example demonstrates how to write generic code that accepts both built-in floating point types, and decimal floating point values from this library
78+
.This https://github.com/cppalliance/decimal/blob/develop/examples/adl.cpp[example] demonstrates how to write generic code that accepts both built-in floating point types, and decimal floating point values from this library
7879
====
7980
[source, c++]
8081
----
@@ -111,7 +112,7 @@ sin(-0.5) = -0.479426
111112

112113
[#examples_literals_constants]
113114
== Literals and Constants
114-
.This example demonstrates how to construct values using literals, and the usage of numerical constants that are provided by the library
115+
.This https://github.com/cppalliance/decimal/blob/develop/examples/literals.cpp[example] demonstrates how to construct values using literals, and the usage of numerical constants that are provided by the library
115116
====
116117
[source, c++]
117118
----
@@ -138,7 +139,7 @@ pass:[{fmt}] support is available starting with pass:[C++14] so long as you have
138139
[#examples_fmt_format]
139140
=== `<fmt/format.hpp>`
140141

141-
.This example demonstrates the various formatting options provided by the library to support usage of pass:[{fmt}]
142+
.This https://github.com/cppalliance/decimal/blob/develop/examples/fmt_format.cpp[example] demonstrates the various formatting options provided by the library to support usage of pass:[{fmt}]
142143
====
143144
[source, c++]
144145
----
@@ -212,7 +213,7 @@ You must include it yourself.
212213

213214
Taking the above example of pass:[{fmt}] and replacing all instances of `namespace fmt` with `namespace std` gives us another working example.
214215

215-
.This example demonstrates how to use `<format>` with the library in-place or in addition to pass:[{fmt}]
216+
.This https://github.com/cppalliance/decimal/blob/develop/examples/format.cpp[example] demonstrates how to use `<format>` with the library in-place or in addition to pass:[{fmt}]
216217
====
217218
[source, c++]
218219
----
@@ -242,7 +243,7 @@ Scientific Format with Specified Precision and Padding:
242243

243244
[#examples_print]
244245
=== `<print>`
245-
.This example demonstrates how to use `<print>` with the library
246+
.This https://github.com/cppalliance/decimal/blob/develop/examples/print.cpp[example] demonstrates how to use `<print>` with the library
246247
====
247248
[source, c++]
248249
----

doc/modules/ROOT/pages/financial_examples.adoc

Lines changed: 37 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,42 @@ https://www.boost.org/LICENSE_1_0.txt
88
= Financial Examples
99
:idprefix: financial_examples_
1010

11-
== Financial Applications
12-
13-
=== Simple Moving Average
14-
15-
In the examples folder there is a file named `moving_average.cpp`.
16-
This example shows how to parse historical stock data from a file and use it.
17-
This serves as a framework for other calculations for securities.
18-
19-
=== Currency Conversion
20-
In the examples folder there is a file named `currency_conversion.cpp`.
21-
This example shows how to simply convert currencies based off a given exchange rate.
11+
Below are a few additional examples as to how the Decimal library can be used in the context of financial applications.
12+
All of these examples can be found in the library `examples/` folder as well.
13+
14+
== Parsing Pricing Data from File
15+
[#examples_money_parsing]
16+
.This https://github.com/cppalliance/decimal/blob/develop/examples/numerical_parsing.cpp[example] demonstrates the numerical differences between parsing of monetary values between using `decimal32_t` and `float`
17+
====
18+
[source, c++]
19+
----
20+
include::example$numerical_parsing.cpp[]
21+
----
22+
23+
.Expected Output
24+
....
25+
Number of data points: 252
26+
Sum from MS Excel: 52151.99
27+
Sum using decimal32_t: 52151.99
28+
Sum using float: 52151.96
29+
....
30+
====
2231

2332
[#examples_boost_math]
24-
== Boost.Math Integration
25-
26-
=== Bollinger Bands
27-
28-
In the examples folder there is a file named `statistics.cpp`.
29-
This example demonstrates how to parse a file, and then leverage Boost.Math to compute statistics of that data set culminating with the values of the Bollinger Bands.
30-
This example could be extended with the simple moving average to create full bands based on the period of the moving average you would like.
33+
== Boost.Math to Calculate Bollinger Bands
34+
.This https://github.com/cppalliance/decimal/blob/develop/examples/statistics.cpp[example] demonstrates how we can use the decimal library with existing Boost.Math facilities to perform statistical analysis
35+
====
36+
[source, c++]
37+
----
38+
include::example$statistics.cpp[]
39+
----
40+
41+
.Expected Output
42+
....
43+
Mean Closing Price: $207.20
44+
Median Closing Price: $214.26
45+
Standard Deviation: $25.45
46+
Upper Bollinger Band: $258.11
47+
Lower Bollinger Band: $156.30
48+
....
49+
====

examples/currency_conversion.cpp

Lines changed: 0 additions & 28 deletions
This file was deleted.

examples/moving_average.cpp

Lines changed: 0 additions & 96 deletions
This file was deleted.

examples/numerical_parsing.cpp

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
// Copyright 2025 Matt Borland
2+
// Distributed under the Boost Software License, Version 1.0.
3+
// https://www.boost.org/LICENSE_1_0.txt
4+
//
5+
// This file briefly demonstrates the difference in results when parsing monetary values between float and decimal32_t
6+
7+
#include "where_file.hpp"
8+
#include <boost/decimal/decimal32_t.hpp> // For type decimal32_t
9+
#include <boost/decimal/charconv.hpp> // For support to <charconv>
10+
#include <boost/decimal/iostream.hpp> // For decimal support to <iostream>
11+
#include <string>
12+
#include <vector>
13+
#include <fstream>
14+
#include <sstream>
15+
#include <limits>
16+
#include <numeric>
17+
#include <iostream>
18+
#include <iomanip>
19+
20+
using boost::decimal::decimal32_t;
21+
22+
template <typename T>
23+
T parse_opening_price(const std::string& line);
24+
25+
template <>
26+
float parse_opening_price<float>(const std::string& line)
27+
{
28+
const auto result {std::stof(line)};
29+
return result;
30+
}
31+
32+
template <>
33+
decimal32_t parse_opening_price<decimal32_t>(const std::string& line)
34+
{
35+
decimal32_t result;
36+
const auto r = from_chars(line, result);
37+
38+
// If we have a parse failure throw std::invalid_argument if the environment supports it,
39+
// using std::invalid_argument which is the same thing thrown by std::stof in the float case
40+
//
41+
// If we are in a no throw environment returning a qNaN will poison our results as well
42+
if (!r)
43+
{
44+
// LCOV_EXCL_START
45+
result = std::numeric_limits<decimal32_t>::quiet_NaN();
46+
BOOST_DECIMAL_THROW_EXCEPTION(std::invalid_argument("Parsing has failed"));
47+
// LCOV_EXCL_STOP
48+
}
49+
50+
return result;
51+
}
52+
53+
template <typename T>
54+
T parse_csv_line(const std::string& line)
55+
{
56+
std::stringstream ss(line);
57+
std::string token;
58+
std::string date;
59+
60+
std::getline(ss, date, ',');
61+
std::getline(ss, token, ',');
62+
63+
return parse_opening_price<T>(token);
64+
}
65+
66+
int main()
67+
{
68+
// We have a CSV file containing one years worth of daily stock data for AAPL
69+
// Here we will show the differences that arise (however small)
70+
// between parsing with float and decimal32_t
71+
72+
// Open and read the CSV file
73+
std::ifstream file(boost::decimal::where_file("AAPL.csv"));
74+
std::string line;
75+
76+
// Skip header line
77+
std::getline(file, line);
78+
79+
std::vector<decimal32_t> decimal_opening_prices;
80+
std::vector<float> float_opening_prices;
81+
82+
// Parse each line once into decimal32_t and once into a float
83+
while (std::getline(file, line))
84+
{
85+
decimal_opening_prices.emplace_back(parse_csv_line<decimal32_t>(line));
86+
float_opening_prices.emplace_back(parse_csv_line<float>(line));
87+
}
88+
89+
// Use std::accumulate to get the sum of all the pricing information in the array
90+
// This will be used to compare the total value parsed
91+
const auto decimal_sum {std::accumulate(decimal_opening_prices.begin(),
92+
decimal_opening_prices.end(), decimal32_t{0})};
93+
94+
const auto float_sum {std::accumulate(float_opening_prices.begin(),
95+
float_opening_prices.end(), float{0})};
96+
97+
// This is the reference value that was found using the sum command of the CSV
98+
// inside Microsoft Excel
99+
const std::string ms_excel_result {"52151.99"};
100+
101+
std::cout << std::setprecision(std::numeric_limits<float>::digits10 + 1)
102+
<< "Number of data points: " << decimal_opening_prices.size() << '\n'
103+
<< " Sum from MS Excel: " << ms_excel_result << '\n'
104+
<< "Sum using decimal32_t: " << decimal_sum << '\n'
105+
<< " Sum using float: " << float_sum << std::endl;
106+
}

0 commit comments

Comments
 (0)