algotradelib
0.0.0.9000
C++ header-only library for algorithmic trading
Toggle main menu visibility
Loading...
Searching...
No Matches
conversion.hpp
Go to the documentation of this file.
1
#pragma once
2
3
#include "
./numeric.hpp
"
4
5
#include <algotradelib/core>
6
7
#include <algorithm>
8
#include <cmath>
9
#include <cstdint>
10
#include <limits>
11
#include <optional>
12
13
namespace
algotradelib
{
14
namespace
analytics
{
15
23
37
inline
Scalar
to_scalar
(
const
Decimal64
& value) {
38
// Every power of ten up to 10^22 is a double, so this product is exact over that range.
39
Scalar
divisor{1};
40
for
(std::uint8_t step = 0; step < value.
scale
(); ++step) {
41
divisor *=
Scalar
(10);
42
}
43
return
static_cast<
Scalar
>
(value.
coefficient
()) / divisor;
44
}
45
60
inline
std::optional<Decimal64>
to_decimal
(
Scalar
value, std::uint8_t scale) {
61
if
(!std::isfinite(value)) {
62
return
std::nullopt;
63
}
64
Scalar
scaled = value;
65
for
(std::uint8_t step = 0; step < scale; ++step) {
66
scaled *=
Scalar
(10);
67
}
68
// `std::round` is half away from zero by definition. Adding 0.5 first rounds the sum: 0.49999999999999994
69
// became 1, and an odd integer near 2^52 moved up by one.
70
const
Scalar
rounded = std::round(scaled);
71
// `INT64_MAX` is not a double: it converts to 2^63, which does not fit, so that bound is exclusive.
72
if
(
73
rounded >=
static_cast<
Scalar
>
(std::numeric_limits<std::int64_t>::max()) ||
74
rounded <
static_cast<
Scalar
>
(std::numeric_limits<std::int64_t>::min())
75
) {
76
return
std::nullopt;
77
}
78
return
Decimal64
(
static_cast<
std::int64_t
>
(rounded), scale);
79
}
80
99
inline
std::optional<Decimal64>
round_scalar_to_tick
(
100
Scalar
value,
101
const
PriceRule
& rule,
102
OrderSide
side,
103
std::uint8_t scale = 0
104
) {
105
const
auto
nearest =
to_decimal
(value, scale);
106
if
(!nearest) {
107
return
std::nullopt;
108
}
109
// `to_decimal` rounds to nearest, which can cross the computed value against the order. Step one
110
// unit back when it did by more than floating-point noise (a few units in the last place).
111
Scalar
scaled = value;
112
for
(std::uint8_t step = 0; step < scale; ++step) {
113
scaled *=
Scalar
(10);
114
}
115
// Each of the `scale` multiplications here can add half a unit in the last place, and a value that
116
// came through `to_scalar` within its bounds carries one more half unit from its division. The
117
// tolerance is wider than that sum: it also absorbs values computed from such inputs.
118
const
Scalar
noise = std::max(
119
Scalar
(1e-9),
120
std::abs(scaled) *
Scalar
(2 * scale + 4) * std::numeric_limits<Scalar>::epsilon()
121
);
122
const
auto
coefficient = nearest->coefficient();
123
const
Scalar
crossed =
static_cast<
Scalar
>
(coefficient) - scaled;
124
auto
exact = *nearest;
125
if
(side == OrderSide::BUY && crossed > noise) {
126
if
(coefficient == std::numeric_limits<std::int64_t>::min()) {
127
return
std::nullopt;
128
}
129
exact =
Decimal64
(coefficient - 1, scale);
130
}
else
if
(side == OrderSide::SELL && -crossed > noise) {
131
if
(coefficient == std::numeric_limits<std::int64_t>::max()) {
132
return
std::nullopt;
133
}
134
exact =
Decimal64
(coefficient + 1, scale);
135
}
136
return
rule.
round_to_tick
(exact, side);
137
}
138
139
}
// namespace analytics
140
}
// namespace algotradelib
algotradelib::Decimal64
An exact signed decimal: an int64 coefficient times 10^-scale.
Definition
types.hpp:297
algotradelib::Decimal64::scale
std::uint8_t scale() const noexcept
Returns the scale.
Definition
types.hpp:405
algotradelib::Decimal64::coefficient
std::int64_t coefficient() const noexcept
Returns the coefficient.
Definition
types.hpp:399
algotradelib::Decimal64::Decimal64
Decimal64()=default
Constructs zero.
algotradelib::analytics
Returns, rolling statistics, indicators and performance metrics over numeric series.
Definition
conversion.hpp:14
algotradelib::analytics::round_scalar_to_tick
std::optional< Decimal64 > round_scalar_to_tick(Scalar value, const PriceRule &rule, OrderSide side, std::uint8_t scale=0)
Converts a computed value into a price an order can carry.
Definition
conversion.hpp:99
algotradelib::analytics::to_scalar
Scalar to_scalar(const Decimal64 &value)
Converts an exact decimal to the nearest Scalar.
Definition
conversion.hpp:37
algotradelib::analytics::to_decimal
std::optional< Decimal64 > to_decimal(Scalar value, std::uint8_t scale)
Converts a Scalar to an exact decimal with a given number of decimal places.
Definition
conversion.hpp:60
algotradelib::math::Scalar
double Scalar
The floating-point type the analytics and math layers compute in (double).
Definition
scalar.hpp:18
algotradelib
The library: broker-neutral types (core), and the modules below.
Definition
conversion.hpp:13
algotradelib::OrderSide
OrderSide
The side of an order: its economic direction, buy or sell.
Definition
types.hpp:1683
numeric.hpp
Re-exports math::Scalar, math::missing and math::observed into analytics.
algotradelib::PriceRule
The price grid (tick sizes) an instrument's order prices must sit on.
Definition
instrument.hpp:150
algotradelib::PriceRule::round_to_tick
std::optional< Decimal64 > round_to_tick(const Decimal64 &price, OrderSide side) const
Rounds a price to its band's tick in the order's favour: a buy rounds down, a sell up.
Definition
instrument.hpp:237
algotradelib
src
analytics
conversion.hpp
Generated by
1.18.0