jg-bignumber 0.0.0-stage → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -0
- package/LICENSE +21 -0
- package/README.md +67 -2
- package/dist/calculations/calculations.d.ts +183 -0
- package/dist/calculations/calculations.js +289 -0
- package/dist/calculations/calculations.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/processing/processing.d.ts +87 -0
- package/dist/processing/processing.js +139 -0
- package/dist/processing/processing.js.map +1 -0
- package/dist/shared/constants.d.ts +2 -0
- package/dist/shared/constants.js +9 -0
- package/dist/shared/constants.js.map +1 -0
- package/dist/shared/errors.d.ts +9 -0
- package/dist/shared/errors.js +11 -0
- package/dist/shared/errors.js.map +1 -0
- package/dist/shared/types.d.ts +20 -0
- package/dist/shared/types.js +2 -0
- package/dist/shared/types.js.map +1 -0
- package/dist/utils/utils.d.ts +49 -0
- package/dist/utils/utils.js +131 -0
- package/dist/utils/utils.js.map +1 -0
- package/dist/validations/validations.d.ts +24 -0
- package/dist/validations/validations.js +41 -0
- package/dist/validations/validations.js.map +1 -0
- package/package.json +62 -3
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 1.0.1
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
|
|
7
|
+
- Published by CI from `jesusgraterol/jg-packages`, with npm provenance. The code is the same as 1.0.0.
|
|
8
|
+
|
|
9
|
+
## 1.0.0
|
|
10
|
+
|
|
11
|
+
The first release of `jg-bignumber`, which replaces `bignumber-utils` 1.1.0.
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- `BigNumber`, the package's own bignumber.js constructor.
|
|
16
|
+
- `ERRORS`, the codes of every error the package throws.
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
|
|
20
|
+
- `decimalPlaces` applies to every rounding mode, including `*_CEIL` and `*_FLOOR`.
|
|
21
|
+
- `NaN` and `±Infinity` are rejected as `INVALID_VALUE`.
|
|
22
|
+
- `calculateWeightedEntry` returns 0 when the amounts add up to 0.
|
|
23
|
+
- The package no longer changes the global bignumber.js configuration, and it uses bignumber.js 11.
|
|
24
|
+
- Errors are `Exception`s from `jg-exception`.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jesus Graterol
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,68 @@
|
|
|
1
|
-
#
|
|
1
|
+
# jg-bignumber
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Exact decimal math with bignumber.js: rounding, formatting, and sum, mean, percentage, and exchange calculations.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install jg-bignumber
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
Every calculation is exact, then rounded to 2 decimal places with `ROUND_HALF_UP` and returned as a number, unless the configuration asks otherwise:
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { calculateSum, processValue, prettifyValue } from 'jg-bignumber';
|
|
17
|
+
|
|
18
|
+
calculateSum([0.1, '0.2', 0.3]); // 0.6, not 0.6000000000000001
|
|
19
|
+
processValue(512.155); // 512.16
|
|
20
|
+
processValue(19.991, { roundingMode: 'ROUND_CEIL' }); // 20
|
|
21
|
+
processValue('0.000001', { decimalPlaces: 6, type: 'string' }); // '0.000001'
|
|
22
|
+
prettifyValue(1234.5, { format: { prefix: '$' } }); // '$1,234.5'
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Percentages and money:
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
import {
|
|
29
|
+
adjustByPercentage,
|
|
30
|
+
calculateExchange,
|
|
31
|
+
calculatePercentageChange,
|
|
32
|
+
calculateWeightedEntry,
|
|
33
|
+
} from 'jg-bignumber';
|
|
34
|
+
|
|
35
|
+
calculatePercentageChange(100, 125); // 25
|
|
36
|
+
adjustByPercentage(100, -10); // 90
|
|
37
|
+
calculateExchange(100, 65000, { decimalPlaces: 8 }); // 0.00153846
|
|
38
|
+
calculateWeightedEntry([
|
|
39
|
+
[100, 2],
|
|
40
|
+
[130, 1],
|
|
41
|
+
]); // 110, the average price weighted by amount
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
`BigNumber` is the package's own bignumber.js constructor, so creating values with it never changes the global bignumber.js configuration.
|
|
45
|
+
|
|
46
|
+
## Coming from `bignumber-utils`
|
|
47
|
+
|
|
48
|
+
| `bignumber-utils` | `jg-bignumber` |
|
|
49
|
+
| ------------------------------------------------------------------------- | ------------------------------------------ |
|
|
50
|
+
| `import … from 'bignumber-utils'` | `import … from 'jg-bignumber'` |
|
|
51
|
+
| `import { BigNumber } from 'bignumber.js'` for values the package accepts | `import { BigNumber } from 'jg-bignumber'` |
|
|
52
|
+
|
|
53
|
+
Changed behavior:
|
|
54
|
+
|
|
55
|
+
- `decimalPlaces` applies to every rounding mode. The `*_CEIL` and `*_FLOOR` modes used to force 0 decimal places; pass `decimalPlaces: 0` for that.
|
|
56
|
+
- `NaN` and `±Infinity` are rejected: `getBigNumber`, `processValue`, and the calculations throw `INVALID_VALUE`, and `isNumber` returns `false`.
|
|
57
|
+
- Importing the package no longer changes the global bignumber.js configuration.
|
|
58
|
+
- `calculateWeightedEntry` returns 0 when the amounts add up to 0, instead of failing.
|
|
59
|
+
- Errors are `Exception`s from `jg-exception`, with the same codes, exported as `ERRORS`.
|
|
60
|
+
- The package uses bignumber.js 11, whose `IBigNumberFormat` adds `negativeSign` and `positiveSign`.
|
|
61
|
+
|
|
62
|
+
## Documentation
|
|
63
|
+
|
|
64
|
+
The full API reference is at https://jg-packages.jesusgraterol.dev/packages/jg-bignumber/.
|
|
65
|
+
|
|
66
|
+
## License
|
|
67
|
+
|
|
68
|
+
[MIT](https://github.com/jesusgraterol/jg-packages/blob/main/packages/jg-bignumber/LICENSE)
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import type { IBigNumberValue, IConfig, IOutput } from '../shared/types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Adds up a list of values. An empty list sums to 0.
|
|
4
|
+
* @param values The values.
|
|
5
|
+
* @param config How the result is processed.
|
|
6
|
+
* @returns The sum.
|
|
7
|
+
* @example
|
|
8
|
+
* calculateSum([0.1, '0.2', 0.3]); // 0.6
|
|
9
|
+
* calculateSum([0.1, 0.2], { type: 'string' }); // '0.3'
|
|
10
|
+
* @throws
|
|
11
|
+
* - INVALID_VALUE: if any of the given values isn't a finite number or BigNumber throws an error
|
|
12
|
+
* - INVALID_DECIMAL_PLACES: if the number of decimal places is invalid for any reason
|
|
13
|
+
* - INVALID_ROUNDING_MODE: if the rounding mode name is not supported
|
|
14
|
+
* - INVALID_TYPE: if the processing type is not supported
|
|
15
|
+
* - INVALID_VALUES_ARRAY: if the provided values arg is not a valid array
|
|
16
|
+
*/
|
|
17
|
+
export declare const calculateSum: <T extends Partial<IConfig>>(values: IBigNumberValue[], config?: T) => IOutput<T>;
|
|
18
|
+
/**
|
|
19
|
+
* Finds the smallest value in a list. An empty list returns 0.
|
|
20
|
+
* @param values The values.
|
|
21
|
+
* @param config How the result is processed.
|
|
22
|
+
* @returns The smallest value.
|
|
23
|
+
* @example
|
|
24
|
+
* calculateMin([3, '1.5', 2]); // 1.5
|
|
25
|
+
* @throws
|
|
26
|
+
* - INVALID_VALUE: if any of the given values isn't a finite number or BigNumber throws an error
|
|
27
|
+
* - INVALID_DECIMAL_PLACES: if the number of decimal places is invalid for any reason
|
|
28
|
+
* - INVALID_ROUNDING_MODE: if the rounding mode name is not supported
|
|
29
|
+
* - INVALID_TYPE: if the processing type is not supported
|
|
30
|
+
* - INVALID_VALUES_ARRAY: if the provided values arg is not a valid array
|
|
31
|
+
*/
|
|
32
|
+
export declare const calculateMin: <T extends Partial<IConfig>>(values: IBigNumberValue[], config?: T) => IOutput<T>;
|
|
33
|
+
/**
|
|
34
|
+
* Finds the largest value in a list. An empty list returns 0.
|
|
35
|
+
* @param values The values.
|
|
36
|
+
* @param config How the result is processed.
|
|
37
|
+
* @returns The largest value.
|
|
38
|
+
* @example
|
|
39
|
+
* calculateMax([3, '1.5', 2]); // 3
|
|
40
|
+
* @throws
|
|
41
|
+
* - INVALID_VALUE: if any of the given values isn't a finite number or BigNumber throws an error
|
|
42
|
+
* - INVALID_DECIMAL_PLACES: if the number of decimal places is invalid for any reason
|
|
43
|
+
* - INVALID_ROUNDING_MODE: if the rounding mode name is not supported
|
|
44
|
+
* - INVALID_TYPE: if the processing type is not supported
|
|
45
|
+
* - INVALID_VALUES_ARRAY: if the provided values arg is not a valid array
|
|
46
|
+
*/
|
|
47
|
+
export declare const calculateMax: <T extends Partial<IConfig>>(values: IBigNumberValue[], config?: T) => IOutput<T>;
|
|
48
|
+
/**
|
|
49
|
+
* Calculates the mean of a list of values. An empty list returns 0.
|
|
50
|
+
* @param values The values.
|
|
51
|
+
* @param config How the result is processed.
|
|
52
|
+
* @returns The mean.
|
|
53
|
+
* @example
|
|
54
|
+
* calculateMean([1, 2, 4]); // 2.33
|
|
55
|
+
* @throws
|
|
56
|
+
* - INVALID_VALUE: if any of the given values isn't a finite number or BigNumber throws an error
|
|
57
|
+
* - INVALID_DECIMAL_PLACES: if the number of decimal places is invalid for any reason
|
|
58
|
+
* - INVALID_ROUNDING_MODE: if the rounding mode name is not supported
|
|
59
|
+
* - INVALID_TYPE: if the processing type is not supported
|
|
60
|
+
* - INVALID_VALUES_ARRAY: if the provided values arg is not a valid array
|
|
61
|
+
*/
|
|
62
|
+
export declare const calculateMean: <T extends Partial<IConfig>>(values: IBigNumberValue[], config?: T) => IOutput<T>;
|
|
63
|
+
/**
|
|
64
|
+
* Calculates the median of a list of values: the middle value, or the mean of the two middle
|
|
65
|
+
* values when the list has an even length. An empty list returns 0.
|
|
66
|
+
* @param values The values.
|
|
67
|
+
* @param config How the result is processed.
|
|
68
|
+
* @returns The median.
|
|
69
|
+
* @example
|
|
70
|
+
* calculateMedian([5, 1, 3]); // 3
|
|
71
|
+
* calculateMedian([4, 1, 3, 2]); // 2.5
|
|
72
|
+
* @throws
|
|
73
|
+
* - INVALID_VALUE: if any of the given values isn't a finite number or BigNumber throws an error
|
|
74
|
+
* - INVALID_DECIMAL_PLACES: if the number of decimal places is invalid for any reason
|
|
75
|
+
* - INVALID_ROUNDING_MODE: if the rounding mode name is not supported
|
|
76
|
+
* - INVALID_TYPE: if the processing type is not supported
|
|
77
|
+
* - INVALID_VALUES_ARRAY: if the provided values arg is not a valid array
|
|
78
|
+
*/
|
|
79
|
+
export declare const calculateMedian: <T extends Partial<IConfig>>(values: IBigNumberValue[], config?: T) => IOutput<T>;
|
|
80
|
+
/**
|
|
81
|
+
* Calculates the percentage a value changed by: positive when it increased, negative when it
|
|
82
|
+
* decreased, and 0 when it didn't change. The largest decrease is -100%, returned whenever the new
|
|
83
|
+
* value is 0 or less.
|
|
84
|
+
* @param oldValue The value before the change.
|
|
85
|
+
* @param newValue The value after the change.
|
|
86
|
+
* @param config How the result is processed.
|
|
87
|
+
* @returns The percentage change.
|
|
88
|
+
* @example
|
|
89
|
+
* calculatePercentageChange(100, 125); // 25
|
|
90
|
+
* calculatePercentageChange(100, 80); // -20
|
|
91
|
+
* calculatePercentageChange(100, 0); // -100
|
|
92
|
+
* @throws
|
|
93
|
+
* - INVALID_VALUE: if any of the given values isn't a finite number or BigNumber throws an error
|
|
94
|
+
* - INVALID_DECIMAL_PLACES: if the number of decimal places is invalid for any reason
|
|
95
|
+
* - INVALID_ROUNDING_MODE: if the rounding mode name is not supported
|
|
96
|
+
* - INVALID_TYPE: if the processing type is not supported
|
|
97
|
+
* - NEGATIVE_VALUE_NOT_ALLOWED: if the oldValue is not positive
|
|
98
|
+
*/
|
|
99
|
+
export declare const calculatePercentageChange: <T extends Partial<IConfig>>(oldValue: IBigNumberValue, newValue: IBigNumberValue, config?: T) => IOutput<T>;
|
|
100
|
+
/**
|
|
101
|
+
* Changes a value by a percentage: a positive percentage increases it, and a negative one
|
|
102
|
+
* decreases it, to 0 at most.
|
|
103
|
+
* @param value The value to change.
|
|
104
|
+
* @param percentage The percentage to change it by.
|
|
105
|
+
* @param config How the result is processed.
|
|
106
|
+
* @returns The changed value.
|
|
107
|
+
* @example
|
|
108
|
+
* adjustByPercentage(100, 25); // 125
|
|
109
|
+
* adjustByPercentage(100, -10); // 90
|
|
110
|
+
* @throws
|
|
111
|
+
* - INVALID_VALUE: if any of the given values isn't a finite number or BigNumber throws an error
|
|
112
|
+
* - INVALID_DECIMAL_PLACES: if the number of decimal places is invalid for any reason
|
|
113
|
+
* - INVALID_ROUNDING_MODE: if the rounding mode name is not supported
|
|
114
|
+
* - INVALID_TYPE: if the processing type is not supported
|
|
115
|
+
* - NEGATIVE_VALUE_NOT_ALLOWED: if the value is not positive
|
|
116
|
+
*/
|
|
117
|
+
export declare const adjustByPercentage: <T extends Partial<IConfig>>(value: IBigNumberValue, percentage: IBigNumberValue, config?: T) => IOutput<T>;
|
|
118
|
+
/**
|
|
119
|
+
* Calculates what percentage of a total a value represents.
|
|
120
|
+
* @param value The part.
|
|
121
|
+
* @param total The total.
|
|
122
|
+
* @param config How the result is processed.
|
|
123
|
+
* @returns The percentage.
|
|
124
|
+
* @example
|
|
125
|
+
* calculatePercentageRepresentation(25, 200); // 12.5
|
|
126
|
+
* @throws
|
|
127
|
+
* - INVALID_VALUE: if any of the given values isn't a finite number or BigNumber throws an error
|
|
128
|
+
* - INVALID_DECIMAL_PLACES: if the number of decimal places is invalid for any reason
|
|
129
|
+
* - INVALID_ROUNDING_MODE: if the rounding mode name is not supported
|
|
130
|
+
* - INVALID_TYPE: if the processing type is not supported
|
|
131
|
+
* - NEGATIVE_VALUE_NOT_ALLOWED: if the value or total are not positive
|
|
132
|
+
*/
|
|
133
|
+
export declare const calculatePercentageRepresentation: <T extends Partial<IConfig>>(value: IBigNumberValue, total: IBigNumberValue, config?: T) => IOutput<T>;
|
|
134
|
+
/**
|
|
135
|
+
* Calculates the amount of an asset an exchange gives for a value at a rate, such as how much
|
|
136
|
+
* BTC 100 USDT buys at 65,000 USDT per BTC.
|
|
137
|
+
* @param value The amount being exchanged.
|
|
138
|
+
* @param rate The price of one unit of the asset received.
|
|
139
|
+
* @param config How the result is processed.
|
|
140
|
+
* @returns The amount received.
|
|
141
|
+
* @example
|
|
142
|
+
* calculateExchange(100, 65000, { decimalPlaces: 8 }); // 0.00153846
|
|
143
|
+
* @throws
|
|
144
|
+
* - INVALID_VALUE: if any of the given values isn't a finite number or BigNumber throws an error
|
|
145
|
+
* - INVALID_DECIMAL_PLACES: if the number of decimal places is invalid for any reason
|
|
146
|
+
* - INVALID_ROUNDING_MODE: if the rounding mode name is not supported
|
|
147
|
+
* - INVALID_TYPE: if the processing type is not supported
|
|
148
|
+
* - NEGATIVE_VALUE_NOT_ALLOWED: if the value or rate are not positive
|
|
149
|
+
*/
|
|
150
|
+
export declare const calculateExchange: <T extends Partial<IConfig>>(value: IBigNumberValue, rate: IBigNumberValue, config?: T) => IOutput<T>;
|
|
151
|
+
/**
|
|
152
|
+
* Calculates the fee charged for an exchange, as a percentage of the value exchanged.
|
|
153
|
+
* @param value The amount being exchanged.
|
|
154
|
+
* @param feePercentage The fee, as a percentage.
|
|
155
|
+
* @param config How the result is processed.
|
|
156
|
+
* @returns The fee.
|
|
157
|
+
* @example
|
|
158
|
+
* calculateExchangeFee(1000, 0.1); // 1
|
|
159
|
+
* @throws
|
|
160
|
+
* - INVALID_VALUE: if any of the given values isn't a finite number or BigNumber throws an error
|
|
161
|
+
* - INVALID_DECIMAL_PLACES: if the number of decimal places is invalid for any reason
|
|
162
|
+
* - INVALID_ROUNDING_MODE: if the rounding mode name is not supported
|
|
163
|
+
* - INVALID_TYPE: if the processing type is not supported
|
|
164
|
+
* - NEGATIVE_VALUE_NOT_ALLOWED: if the value or feePercentage are not positive
|
|
165
|
+
*/
|
|
166
|
+
export declare const calculateExchangeFee: <T extends Partial<IConfig>>(value: IBigNumberValue, feePercentage: IBigNumberValue, config?: T) => IOutput<T>;
|
|
167
|
+
/**
|
|
168
|
+
* Calculates the average entry price of a position bought in several trades, weighting each price
|
|
169
|
+
* by the amount bought. An empty list, or one whose amounts add up to 0, returns 0.
|
|
170
|
+
* @param trades The trades, each as a `[price, amount]` tuple.
|
|
171
|
+
* @param config How the result is processed.
|
|
172
|
+
* @returns The weighted average price.
|
|
173
|
+
* @example
|
|
174
|
+
* calculateWeightedEntry([[100, 2], [130, 1]]); // 110
|
|
175
|
+
* calculateWeightedEntry([]); // 0
|
|
176
|
+
* @throws
|
|
177
|
+
* - INVALID_VALUE: if any of the given values isn't a finite number or BigNumber throws an error
|
|
178
|
+
* - INVALID_DECIMAL_PLACES: if the number of decimal places is invalid for any reason
|
|
179
|
+
* - INVALID_ROUNDING_MODE: if the rounding mode name is not supported
|
|
180
|
+
* - INVALID_TYPE: if the processing type is not supported
|
|
181
|
+
* - INVALID_VALUES_ARRAY: if the provided values arg is not a valid array
|
|
182
|
+
*/
|
|
183
|
+
export declare const calculateWeightedEntry: <T extends Partial<IConfig>>(trades: [IBigNumberValue, IBigNumberValue][], config?: T) => IOutput<T>;
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
import { BigNumber } from '../shared/constants.js';
|
|
2
|
+
import { getBigNumber, processValue } from '../processing/processing.js';
|
|
3
|
+
import { sortBigNumbers } from '../utils/utils.js';
|
|
4
|
+
import { validatePositiveValue, validateValuesArray } from '../validations/validations.js';
|
|
5
|
+
/*
|
|
6
|
+
* Essential calculations
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Adds up a list of values. An empty list sums to 0.
|
|
10
|
+
* @param values The values.
|
|
11
|
+
* @param config How the result is processed.
|
|
12
|
+
* @returns The sum.
|
|
13
|
+
* @example
|
|
14
|
+
* calculateSum([0.1, '0.2', 0.3]); // 0.6
|
|
15
|
+
* calculateSum([0.1, 0.2], { type: 'string' }); // '0.3'
|
|
16
|
+
* @throws
|
|
17
|
+
* - INVALID_VALUE: if any of the given values isn't a finite number or BigNumber throws an error
|
|
18
|
+
* - INVALID_DECIMAL_PLACES: if the number of decimal places is invalid for any reason
|
|
19
|
+
* - INVALID_ROUNDING_MODE: if the rounding mode name is not supported
|
|
20
|
+
* - INVALID_TYPE: if the processing type is not supported
|
|
21
|
+
* - INVALID_VALUES_ARRAY: if the provided values arg is not a valid array
|
|
22
|
+
*/
|
|
23
|
+
export const calculateSum = (values, config) => {
|
|
24
|
+
validateValuesArray(values, 'calculateSum');
|
|
25
|
+
return processValue(values.length > 0 ? BigNumber.sum(...values) : 0, config);
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Finds the smallest value in a list. An empty list returns 0.
|
|
29
|
+
* @param values The values.
|
|
30
|
+
* @param config How the result is processed.
|
|
31
|
+
* @returns The smallest value.
|
|
32
|
+
* @example
|
|
33
|
+
* calculateMin([3, '1.5', 2]); // 1.5
|
|
34
|
+
* @throws
|
|
35
|
+
* - INVALID_VALUE: if any of the given values isn't a finite number or BigNumber throws an error
|
|
36
|
+
* - INVALID_DECIMAL_PLACES: if the number of decimal places is invalid for any reason
|
|
37
|
+
* - INVALID_ROUNDING_MODE: if the rounding mode name is not supported
|
|
38
|
+
* - INVALID_TYPE: if the processing type is not supported
|
|
39
|
+
* - INVALID_VALUES_ARRAY: if the provided values arg is not a valid array
|
|
40
|
+
*/
|
|
41
|
+
export const calculateMin = (values, config) => {
|
|
42
|
+
validateValuesArray(values, 'calculateMin');
|
|
43
|
+
return processValue(values.length > 0 ? BigNumber.min(...values) : 0, config);
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Finds the largest value in a list. An empty list returns 0.
|
|
47
|
+
* @param values The values.
|
|
48
|
+
* @param config How the result is processed.
|
|
49
|
+
* @returns The largest value.
|
|
50
|
+
* @example
|
|
51
|
+
* calculateMax([3, '1.5', 2]); // 3
|
|
52
|
+
* @throws
|
|
53
|
+
* - INVALID_VALUE: if any of the given values isn't a finite number or BigNumber throws an error
|
|
54
|
+
* - INVALID_DECIMAL_PLACES: if the number of decimal places is invalid for any reason
|
|
55
|
+
* - INVALID_ROUNDING_MODE: if the rounding mode name is not supported
|
|
56
|
+
* - INVALID_TYPE: if the processing type is not supported
|
|
57
|
+
* - INVALID_VALUES_ARRAY: if the provided values arg is not a valid array
|
|
58
|
+
*/
|
|
59
|
+
export const calculateMax = (values, config) => {
|
|
60
|
+
validateValuesArray(values, 'calculateMax');
|
|
61
|
+
return processValue(values.length > 0 ? BigNumber.max(...values) : 0, config);
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* Calculates the mean of a list of values. An empty list returns 0.
|
|
65
|
+
* @param values The values.
|
|
66
|
+
* @param config How the result is processed.
|
|
67
|
+
* @returns The mean.
|
|
68
|
+
* @example
|
|
69
|
+
* calculateMean([1, 2, 4]); // 2.33
|
|
70
|
+
* @throws
|
|
71
|
+
* - INVALID_VALUE: if any of the given values isn't a finite number or BigNumber throws an error
|
|
72
|
+
* - INVALID_DECIMAL_PLACES: if the number of decimal places is invalid for any reason
|
|
73
|
+
* - INVALID_ROUNDING_MODE: if the rounding mode name is not supported
|
|
74
|
+
* - INVALID_TYPE: if the processing type is not supported
|
|
75
|
+
* - INVALID_VALUES_ARRAY: if the provided values arg is not a valid array
|
|
76
|
+
*/
|
|
77
|
+
export const calculateMean = (values, config) => {
|
|
78
|
+
validateValuesArray(values, 'calculateMean');
|
|
79
|
+
if (values.length > 0) {
|
|
80
|
+
return processValue(BigNumber.sum(...values).dividedBy(values.length), config);
|
|
81
|
+
}
|
|
82
|
+
return processValue(0, config);
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* Calculates the median of a list of values: the middle value, or the mean of the two middle
|
|
86
|
+
* values when the list has an even length. An empty list returns 0.
|
|
87
|
+
* @param values The values.
|
|
88
|
+
* @param config How the result is processed.
|
|
89
|
+
* @returns The median.
|
|
90
|
+
* @example
|
|
91
|
+
* calculateMedian([5, 1, 3]); // 3
|
|
92
|
+
* calculateMedian([4, 1, 3, 2]); // 2.5
|
|
93
|
+
* @throws
|
|
94
|
+
* - INVALID_VALUE: if any of the given values isn't a finite number or BigNumber throws an error
|
|
95
|
+
* - INVALID_DECIMAL_PLACES: if the number of decimal places is invalid for any reason
|
|
96
|
+
* - INVALID_ROUNDING_MODE: if the rounding mode name is not supported
|
|
97
|
+
* - INVALID_TYPE: if the processing type is not supported
|
|
98
|
+
* - INVALID_VALUES_ARRAY: if the provided values arg is not a valid array
|
|
99
|
+
*/
|
|
100
|
+
export const calculateMedian = (values, config) => {
|
|
101
|
+
validateValuesArray(values, 'calculateMedian');
|
|
102
|
+
if (values.length === 0) {
|
|
103
|
+
return processValue(0, config);
|
|
104
|
+
}
|
|
105
|
+
const half = Math.floor(values.length / 2);
|
|
106
|
+
const sorted = values.map(getBigNumber).sort(sortBigNumbers('asc'));
|
|
107
|
+
const middle = sorted[half];
|
|
108
|
+
const median = values.length % 2 === 1 ? middle : sorted[half - 1].plus(middle).dividedBy(2);
|
|
109
|
+
return processValue(median, config);
|
|
110
|
+
};
|
|
111
|
+
/*
|
|
112
|
+
* Percentage calculations
|
|
113
|
+
*/
|
|
114
|
+
/**
|
|
115
|
+
* Calculates the percentage a value changed by: positive when it increased, negative when it
|
|
116
|
+
* decreased, and 0 when it didn't change. The largest decrease is -100%, returned whenever the new
|
|
117
|
+
* value is 0 or less.
|
|
118
|
+
* @param oldValue The value before the change.
|
|
119
|
+
* @param newValue The value after the change.
|
|
120
|
+
* @param config How the result is processed.
|
|
121
|
+
* @returns The percentage change.
|
|
122
|
+
* @example
|
|
123
|
+
* calculatePercentageChange(100, 125); // 25
|
|
124
|
+
* calculatePercentageChange(100, 80); // -20
|
|
125
|
+
* calculatePercentageChange(100, 0); // -100
|
|
126
|
+
* @throws
|
|
127
|
+
* - INVALID_VALUE: if any of the given values isn't a finite number or BigNumber throws an error
|
|
128
|
+
* - INVALID_DECIMAL_PLACES: if the number of decimal places is invalid for any reason
|
|
129
|
+
* - INVALID_ROUNDING_MODE: if the rounding mode name is not supported
|
|
130
|
+
* - INVALID_TYPE: if the processing type is not supported
|
|
131
|
+
* - NEGATIVE_VALUE_NOT_ALLOWED: if the oldValue is not positive
|
|
132
|
+
*/
|
|
133
|
+
export const calculatePercentageChange = (oldValue, newValue, config) => {
|
|
134
|
+
const oldValueBN = getBigNumber(oldValue);
|
|
135
|
+
const newValueBN = getBigNumber(newValue);
|
|
136
|
+
validatePositiveValue(oldValueBN);
|
|
137
|
+
let change;
|
|
138
|
+
if (newValueBN.isGreaterThan(oldValueBN)) {
|
|
139
|
+
change = newValueBN.minus(oldValueBN).dividedBy(oldValueBN).times(100);
|
|
140
|
+
}
|
|
141
|
+
else if (oldValueBN.isGreaterThan(newValueBN)) {
|
|
142
|
+
change = newValueBN.isGreaterThan(0)
|
|
143
|
+
? oldValueBN.minus(newValueBN).dividedBy(oldValueBN).times(100).negated()
|
|
144
|
+
: getBigNumber(-100);
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
change = getBigNumber(0);
|
|
148
|
+
}
|
|
149
|
+
return processValue(change, config);
|
|
150
|
+
};
|
|
151
|
+
/**
|
|
152
|
+
* Changes a value by a percentage: a positive percentage increases it, and a negative one
|
|
153
|
+
* decreases it, to 0 at most.
|
|
154
|
+
* @param value The value to change.
|
|
155
|
+
* @param percentage The percentage to change it by.
|
|
156
|
+
* @param config How the result is processed.
|
|
157
|
+
* @returns The changed value.
|
|
158
|
+
* @example
|
|
159
|
+
* adjustByPercentage(100, 25); // 125
|
|
160
|
+
* adjustByPercentage(100, -10); // 90
|
|
161
|
+
* @throws
|
|
162
|
+
* - INVALID_VALUE: if any of the given values isn't a finite number or BigNumber throws an error
|
|
163
|
+
* - INVALID_DECIMAL_PLACES: if the number of decimal places is invalid for any reason
|
|
164
|
+
* - INVALID_ROUNDING_MODE: if the rounding mode name is not supported
|
|
165
|
+
* - INVALID_TYPE: if the processing type is not supported
|
|
166
|
+
* - NEGATIVE_VALUE_NOT_ALLOWED: if the value is not positive
|
|
167
|
+
*/
|
|
168
|
+
export const adjustByPercentage = (value, percentage, config) => {
|
|
169
|
+
const valueBN = getBigNumber(value);
|
|
170
|
+
const percentageBN = getBigNumber(percentage);
|
|
171
|
+
validatePositiveValue(valueBN);
|
|
172
|
+
let adjusted;
|
|
173
|
+
if (percentageBN.isGreaterThan(0)) {
|
|
174
|
+
adjusted = percentageBN.dividedBy(100).plus(1).times(valueBN);
|
|
175
|
+
}
|
|
176
|
+
else if (percentageBN.isLessThan(0)) {
|
|
177
|
+
adjusted = percentageBN.isGreaterThan(-100)
|
|
178
|
+
? percentageBN.times(-1).dividedBy(100).minus(1).times(valueBN).times(-1)
|
|
179
|
+
: getBigNumber(0);
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
adjusted = valueBN;
|
|
183
|
+
}
|
|
184
|
+
return processValue(adjusted, config);
|
|
185
|
+
};
|
|
186
|
+
/**
|
|
187
|
+
* Calculates what percentage of a total a value represents.
|
|
188
|
+
* @param value The part.
|
|
189
|
+
* @param total The total.
|
|
190
|
+
* @param config How the result is processed.
|
|
191
|
+
* @returns The percentage.
|
|
192
|
+
* @example
|
|
193
|
+
* calculatePercentageRepresentation(25, 200); // 12.5
|
|
194
|
+
* @throws
|
|
195
|
+
* - INVALID_VALUE: if any of the given values isn't a finite number or BigNumber throws an error
|
|
196
|
+
* - INVALID_DECIMAL_PLACES: if the number of decimal places is invalid for any reason
|
|
197
|
+
* - INVALID_ROUNDING_MODE: if the rounding mode name is not supported
|
|
198
|
+
* - INVALID_TYPE: if the processing type is not supported
|
|
199
|
+
* - NEGATIVE_VALUE_NOT_ALLOWED: if the value or total are not positive
|
|
200
|
+
*/
|
|
201
|
+
export const calculatePercentageRepresentation = (value, total, config) => {
|
|
202
|
+
const valueBN = getBigNumber(value);
|
|
203
|
+
const totalBN = getBigNumber(total);
|
|
204
|
+
validatePositiveValue(valueBN, true);
|
|
205
|
+
validatePositiveValue(totalBN);
|
|
206
|
+
return processValue(valueBN.times(100).dividedBy(totalBN), config);
|
|
207
|
+
};
|
|
208
|
+
/*
|
|
209
|
+
* Financial calculations
|
|
210
|
+
*/
|
|
211
|
+
/**
|
|
212
|
+
* Calculates the amount of an asset an exchange gives for a value at a rate, such as how much
|
|
213
|
+
* BTC 100 USDT buys at 65,000 USDT per BTC.
|
|
214
|
+
* @param value The amount being exchanged.
|
|
215
|
+
* @param rate The price of one unit of the asset received.
|
|
216
|
+
* @param config How the result is processed.
|
|
217
|
+
* @returns The amount received.
|
|
218
|
+
* @example
|
|
219
|
+
* calculateExchange(100, 65000, { decimalPlaces: 8 }); // 0.00153846
|
|
220
|
+
* @throws
|
|
221
|
+
* - INVALID_VALUE: if any of the given values isn't a finite number or BigNumber throws an error
|
|
222
|
+
* - INVALID_DECIMAL_PLACES: if the number of decimal places is invalid for any reason
|
|
223
|
+
* - INVALID_ROUNDING_MODE: if the rounding mode name is not supported
|
|
224
|
+
* - INVALID_TYPE: if the processing type is not supported
|
|
225
|
+
* - NEGATIVE_VALUE_NOT_ALLOWED: if the value or rate are not positive
|
|
226
|
+
*/
|
|
227
|
+
export const calculateExchange = (value, rate, config) => {
|
|
228
|
+
const valueBN = getBigNumber(value);
|
|
229
|
+
const rateBN = getBigNumber(rate);
|
|
230
|
+
validatePositiveValue(valueBN);
|
|
231
|
+
validatePositiveValue(rateBN);
|
|
232
|
+
return processValue(valueBN.dividedBy(rateBN), config);
|
|
233
|
+
};
|
|
234
|
+
/**
|
|
235
|
+
* Calculates the fee charged for an exchange, as a percentage of the value exchanged.
|
|
236
|
+
* @param value The amount being exchanged.
|
|
237
|
+
* @param feePercentage The fee, as a percentage.
|
|
238
|
+
* @param config How the result is processed.
|
|
239
|
+
* @returns The fee.
|
|
240
|
+
* @example
|
|
241
|
+
* calculateExchangeFee(1000, 0.1); // 1
|
|
242
|
+
* @throws
|
|
243
|
+
* - INVALID_VALUE: if any of the given values isn't a finite number or BigNumber throws an error
|
|
244
|
+
* - INVALID_DECIMAL_PLACES: if the number of decimal places is invalid for any reason
|
|
245
|
+
* - INVALID_ROUNDING_MODE: if the rounding mode name is not supported
|
|
246
|
+
* - INVALID_TYPE: if the processing type is not supported
|
|
247
|
+
* - NEGATIVE_VALUE_NOT_ALLOWED: if the value or feePercentage are not positive
|
|
248
|
+
*/
|
|
249
|
+
export const calculateExchangeFee = (value, feePercentage, config) => {
|
|
250
|
+
const valueBN = getBigNumber(value);
|
|
251
|
+
const feePercentageBN = getBigNumber(feePercentage);
|
|
252
|
+
validatePositiveValue(valueBN);
|
|
253
|
+
validatePositiveValue(feePercentageBN, true);
|
|
254
|
+
return processValue(feePercentageBN.times(valueBN).dividedBy(100), config);
|
|
255
|
+
};
|
|
256
|
+
/**
|
|
257
|
+
* Calculates the average entry price of a position bought in several trades, weighting each price
|
|
258
|
+
* by the amount bought. An empty list, or one whose amounts add up to 0, returns 0.
|
|
259
|
+
* @param trades The trades, each as a `[price, amount]` tuple.
|
|
260
|
+
* @param config How the result is processed.
|
|
261
|
+
* @returns The weighted average price.
|
|
262
|
+
* @example
|
|
263
|
+
* calculateWeightedEntry([[100, 2], [130, 1]]); // 110
|
|
264
|
+
* calculateWeightedEntry([]); // 0
|
|
265
|
+
* @throws
|
|
266
|
+
* - INVALID_VALUE: if any of the given values isn't a finite number or BigNumber throws an error
|
|
267
|
+
* - INVALID_DECIMAL_PLACES: if the number of decimal places is invalid for any reason
|
|
268
|
+
* - INVALID_ROUNDING_MODE: if the rounding mode name is not supported
|
|
269
|
+
* - INVALID_TYPE: if the processing type is not supported
|
|
270
|
+
* - INVALID_VALUES_ARRAY: if the provided values arg is not a valid array
|
|
271
|
+
*/
|
|
272
|
+
export const calculateWeightedEntry = (trades, config) => {
|
|
273
|
+
validateValuesArray(trades, 'calculateWeightedEntry');
|
|
274
|
+
if (trades.length === 0) {
|
|
275
|
+
return processValue(0, config);
|
|
276
|
+
}
|
|
277
|
+
let priceTimesShares = getBigNumber(0);
|
|
278
|
+
let totalShares = getBigNumber(0);
|
|
279
|
+
trades.forEach(([price, amount]) => {
|
|
280
|
+
const amountBN = getBigNumber(amount);
|
|
281
|
+
priceTimesShares = priceTimesShares.plus(getBigNumber(price).times(amountBN));
|
|
282
|
+
totalShares = totalShares.plus(amountBN);
|
|
283
|
+
});
|
|
284
|
+
if (totalShares.isZero()) {
|
|
285
|
+
return processValue(0, config);
|
|
286
|
+
}
|
|
287
|
+
return processValue(priceTimesShares.dividedBy(totalShares), config);
|
|
288
|
+
};
|
|
289
|
+
//# sourceMappingURL=calculations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"calculations.js","sourceRoot":"","sources":["../../src/calculations/calculations.ts"],"names":[],"mappings":"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","sourcesContent":["import { BigNumber } from '../shared/constants.js';\nimport type { IBigNumber, IBigNumberValue, IConfig, IOutput } from '../shared/types.js';\nimport { getBigNumber, processValue } from '../processing/processing.js';\nimport { sortBigNumbers } from '../utils/utils.js';\nimport { validatePositiveValue, validateValuesArray } from '../validations/validations.js';\n\n/*\n * Essential calculations\n */\n\n/**\n * Adds up a list of values. An empty list sums to 0.\n * @param values The values.\n * @param config How the result is processed.\n * @returns The sum.\n * @example\n * calculateSum([0.1, '0.2', 0.3]); // 0.6\n * calculateSum([0.1, 0.2], { type: 'string' }); // '0.3'\n * @throws\n * - INVALID_VALUE: if any of the given values isn't a finite number or BigNumber throws an error\n * - INVALID_DECIMAL_PLACES: if the number of decimal places is invalid for any reason\n * - INVALID_ROUNDING_MODE: if the rounding mode name is not supported\n * - INVALID_TYPE: if the processing type is not supported\n * - INVALID_VALUES_ARRAY: if the provided values arg is not a valid array\n */\nexport const calculateSum = <T extends Partial<IConfig>>(\n values: IBigNumberValue[],\n config?: T,\n): IOutput<T> => {\n validateValuesArray(values, 'calculateSum');\n return processValue(values.length > 0 ? BigNumber.sum(...values) : 0, config);\n};\n\n/**\n * Finds the smallest value in a list. An empty list returns 0.\n * @param values The values.\n * @param config How the result is processed.\n * @returns The smallest value.\n * @example\n * calculateMin([3, '1.5', 2]); // 1.5\n * @throws\n * - INVALID_VALUE: if any of the given values isn't a finite number or BigNumber throws an error\n * - INVALID_DECIMAL_PLACES: if the number of decimal places is invalid for any reason\n * - INVALID_ROUNDING_MODE: if the rounding mode name is not supported\n * - INVALID_TYPE: if the processing type is not supported\n * - INVALID_VALUES_ARRAY: if the provided values arg is not a valid array\n */\nexport const calculateMin = <T extends Partial<IConfig>>(\n values: IBigNumberValue[],\n config?: T,\n): IOutput<T> => {\n validateValuesArray(values, 'calculateMin');\n return processValue(values.length > 0 ? BigNumber.min(...values) : 0, config);\n};\n\n/**\n * Finds the largest value in a list. An empty list returns 0.\n * @param values The values.\n * @param config How the result is processed.\n * @returns The largest value.\n * @example\n * calculateMax([3, '1.5', 2]); // 3\n * @throws\n * - INVALID_VALUE: if any of the given values isn't a finite number or BigNumber throws an error\n * - INVALID_DECIMAL_PLACES: if the number of decimal places is invalid for any reason\n * - INVALID_ROUNDING_MODE: if the rounding mode name is not supported\n * - INVALID_TYPE: if the processing type is not supported\n * - INVALID_VALUES_ARRAY: if the provided values arg is not a valid array\n */\nexport const calculateMax = <T extends Partial<IConfig>>(\n values: IBigNumberValue[],\n config?: T,\n): IOutput<T> => {\n validateValuesArray(values, 'calculateMax');\n return processValue(values.length > 0 ? BigNumber.max(...values) : 0, config);\n};\n\n/**\n * Calculates the mean of a list of values. An empty list returns 0.\n * @param values The values.\n * @param config How the result is processed.\n * @returns The mean.\n * @example\n * calculateMean([1, 2, 4]); // 2.33\n * @throws\n * - INVALID_VALUE: if any of the given values isn't a finite number or BigNumber throws an error\n * - INVALID_DECIMAL_PLACES: if the number of decimal places is invalid for any reason\n * - INVALID_ROUNDING_MODE: if the rounding mode name is not supported\n * - INVALID_TYPE: if the processing type is not supported\n * - INVALID_VALUES_ARRAY: if the provided values arg is not a valid array\n */\nexport const calculateMean = <T extends Partial<IConfig>>(\n values: IBigNumberValue[],\n config?: T,\n): IOutput<T> => {\n validateValuesArray(values, 'calculateMean');\n if (values.length > 0) {\n return processValue(BigNumber.sum(...values).dividedBy(values.length), config);\n }\n return processValue(0, config);\n};\n\n/**\n * Calculates the median of a list of values: the middle value, or the mean of the two middle\n * values when the list has an even length. An empty list returns 0.\n * @param values The values.\n * @param config How the result is processed.\n * @returns The median.\n * @example\n * calculateMedian([5, 1, 3]); // 3\n * calculateMedian([4, 1, 3, 2]); // 2.5\n * @throws\n * - INVALID_VALUE: if any of the given values isn't a finite number or BigNumber throws an error\n * - INVALID_DECIMAL_PLACES: if the number of decimal places is invalid for any reason\n * - INVALID_ROUNDING_MODE: if the rounding mode name is not supported\n * - INVALID_TYPE: if the processing type is not supported\n * - INVALID_VALUES_ARRAY: if the provided values arg is not a valid array\n */\nexport const calculateMedian = <T extends Partial<IConfig>>(\n values: IBigNumberValue[],\n config?: T,\n): IOutput<T> => {\n validateValuesArray(values, 'calculateMedian');\n if (values.length === 0) {\n return processValue(0, config);\n }\n const half = Math.floor(values.length / 2);\n const sorted = values.map(getBigNumber).sort(sortBigNumbers('asc'));\n const middle = sorted[half] as IBigNumber;\n const median =\n values.length % 2 === 1 ? middle : (sorted[half - 1] as IBigNumber).plus(middle).dividedBy(2);\n return processValue(median, config);\n};\n\n/*\n * Percentage calculations\n */\n\n/**\n * Calculates the percentage a value changed by: positive when it increased, negative when it\n * decreased, and 0 when it didn't change. The largest decrease is -100%, returned whenever the new\n * value is 0 or less.\n * @param oldValue The value before the change.\n * @param newValue The value after the change.\n * @param config How the result is processed.\n * @returns The percentage change.\n * @example\n * calculatePercentageChange(100, 125); // 25\n * calculatePercentageChange(100, 80); // -20\n * calculatePercentageChange(100, 0); // -100\n * @throws\n * - INVALID_VALUE: if any of the given values isn't a finite number or BigNumber throws an error\n * - INVALID_DECIMAL_PLACES: if the number of decimal places is invalid for any reason\n * - INVALID_ROUNDING_MODE: if the rounding mode name is not supported\n * - INVALID_TYPE: if the processing type is not supported\n * - NEGATIVE_VALUE_NOT_ALLOWED: if the oldValue is not positive\n */\nexport const calculatePercentageChange = <T extends Partial<IConfig>>(\n oldValue: IBigNumberValue,\n newValue: IBigNumberValue,\n config?: T,\n): IOutput<T> => {\n const oldValueBN = getBigNumber(oldValue);\n const newValueBN = getBigNumber(newValue);\n validatePositiveValue(oldValueBN);\n\n let change: IBigNumber;\n if (newValueBN.isGreaterThan(oldValueBN)) {\n change = newValueBN.minus(oldValueBN).dividedBy(oldValueBN).times(100);\n } else if (oldValueBN.isGreaterThan(newValueBN)) {\n change = newValueBN.isGreaterThan(0)\n ? oldValueBN.minus(newValueBN).dividedBy(oldValueBN).times(100).negated()\n : getBigNumber(-100);\n } else {\n change = getBigNumber(0);\n }\n return processValue(change, config);\n};\n\n/**\n * Changes a value by a percentage: a positive percentage increases it, and a negative one\n * decreases it, to 0 at most.\n * @param value The value to change.\n * @param percentage The percentage to change it by.\n * @param config How the result is processed.\n * @returns The changed value.\n * @example\n * adjustByPercentage(100, 25); // 125\n * adjustByPercentage(100, -10); // 90\n * @throws\n * - INVALID_VALUE: if any of the given values isn't a finite number or BigNumber throws an error\n * - INVALID_DECIMAL_PLACES: if the number of decimal places is invalid for any reason\n * - INVALID_ROUNDING_MODE: if the rounding mode name is not supported\n * - INVALID_TYPE: if the processing type is not supported\n * - NEGATIVE_VALUE_NOT_ALLOWED: if the value is not positive\n */\nexport const adjustByPercentage = <T extends Partial<IConfig>>(\n value: IBigNumberValue,\n percentage: IBigNumberValue,\n config?: T,\n): IOutput<T> => {\n const valueBN = getBigNumber(value);\n const percentageBN = getBigNumber(percentage);\n validatePositiveValue(valueBN);\n\n let adjusted: IBigNumber;\n if (percentageBN.isGreaterThan(0)) {\n adjusted = percentageBN.dividedBy(100).plus(1).times(valueBN);\n } else if (percentageBN.isLessThan(0)) {\n adjusted = percentageBN.isGreaterThan(-100)\n ? percentageBN.times(-1).dividedBy(100).minus(1).times(valueBN).times(-1)\n : getBigNumber(0);\n } else {\n adjusted = valueBN;\n }\n return processValue(adjusted, config);\n};\n\n/**\n * Calculates what percentage of a total a value represents.\n * @param value The part.\n * @param total The total.\n * @param config How the result is processed.\n * @returns The percentage.\n * @example\n * calculatePercentageRepresentation(25, 200); // 12.5\n * @throws\n * - INVALID_VALUE: if any of the given values isn't a finite number or BigNumber throws an error\n * - INVALID_DECIMAL_PLACES: if the number of decimal places is invalid for any reason\n * - INVALID_ROUNDING_MODE: if the rounding mode name is not supported\n * - INVALID_TYPE: if the processing type is not supported\n * - NEGATIVE_VALUE_NOT_ALLOWED: if the value or total are not positive\n */\nexport const calculatePercentageRepresentation = <T extends Partial<IConfig>>(\n value: IBigNumberValue,\n total: IBigNumberValue,\n config?: T,\n): IOutput<T> => {\n const valueBN = getBigNumber(value);\n const totalBN = getBigNumber(total);\n validatePositiveValue(valueBN, true);\n validatePositiveValue(totalBN);\n return processValue(valueBN.times(100).dividedBy(totalBN), config);\n};\n\n/*\n * Financial calculations\n */\n\n/**\n * Calculates the amount of an asset an exchange gives for a value at a rate, such as how much\n * BTC 100 USDT buys at 65,000 USDT per BTC.\n * @param value The amount being exchanged.\n * @param rate The price of one unit of the asset received.\n * @param config How the result is processed.\n * @returns The amount received.\n * @example\n * calculateExchange(100, 65000, { decimalPlaces: 8 }); // 0.00153846\n * @throws\n * - INVALID_VALUE: if any of the given values isn't a finite number or BigNumber throws an error\n * - INVALID_DECIMAL_PLACES: if the number of decimal places is invalid for any reason\n * - INVALID_ROUNDING_MODE: if the rounding mode name is not supported\n * - INVALID_TYPE: if the processing type is not supported\n * - NEGATIVE_VALUE_NOT_ALLOWED: if the value or rate are not positive\n */\nexport const calculateExchange = <T extends Partial<IConfig>>(\n value: IBigNumberValue,\n rate: IBigNumberValue,\n config?: T,\n): IOutput<T> => {\n const valueBN = getBigNumber(value);\n const rateBN = getBigNumber(rate);\n validatePositiveValue(valueBN);\n validatePositiveValue(rateBN);\n return processValue(valueBN.dividedBy(rateBN), config);\n};\n\n/**\n * Calculates the fee charged for an exchange, as a percentage of the value exchanged.\n * @param value The amount being exchanged.\n * @param feePercentage The fee, as a percentage.\n * @param config How the result is processed.\n * @returns The fee.\n * @example\n * calculateExchangeFee(1000, 0.1); // 1\n * @throws\n * - INVALID_VALUE: if any of the given values isn't a finite number or BigNumber throws an error\n * - INVALID_DECIMAL_PLACES: if the number of decimal places is invalid for any reason\n * - INVALID_ROUNDING_MODE: if the rounding mode name is not supported\n * - INVALID_TYPE: if the processing type is not supported\n * - NEGATIVE_VALUE_NOT_ALLOWED: if the value or feePercentage are not positive\n */\nexport const calculateExchangeFee = <T extends Partial<IConfig>>(\n value: IBigNumberValue,\n feePercentage: IBigNumberValue,\n config?: T,\n): IOutput<T> => {\n const valueBN = getBigNumber(value);\n const feePercentageBN = getBigNumber(feePercentage);\n validatePositiveValue(valueBN);\n validatePositiveValue(feePercentageBN, true);\n return processValue(feePercentageBN.times(valueBN).dividedBy(100), config);\n};\n\n/**\n * Calculates the average entry price of a position bought in several trades, weighting each price\n * by the amount bought. An empty list, or one whose amounts add up to 0, returns 0.\n * @param trades The trades, each as a `[price, amount]` tuple.\n * @param config How the result is processed.\n * @returns The weighted average price.\n * @example\n * calculateWeightedEntry([[100, 2], [130, 1]]); // 110\n * calculateWeightedEntry([]); // 0\n * @throws\n * - INVALID_VALUE: if any of the given values isn't a finite number or BigNumber throws an error\n * - INVALID_DECIMAL_PLACES: if the number of decimal places is invalid for any reason\n * - INVALID_ROUNDING_MODE: if the rounding mode name is not supported\n * - INVALID_TYPE: if the processing type is not supported\n * - INVALID_VALUES_ARRAY: if the provided values arg is not a valid array\n */\nexport const calculateWeightedEntry = <T extends Partial<IConfig>>(\n trades: [IBigNumberValue, IBigNumberValue][],\n config?: T,\n): IOutput<T> => {\n validateValuesArray(trades, 'calculateWeightedEntry');\n if (trades.length === 0) {\n return processValue(0, config);\n }\n let priceTimesShares = getBigNumber(0);\n let totalShares = getBigNumber(0);\n trades.forEach(([price, amount]) => {\n const amountBN = getBigNumber(amount);\n priceTimesShares = priceTimesShares.plus(getBigNumber(price).times(amountBN));\n totalShares = totalShares.plus(amountBN);\n });\n if (totalShares.isZero()) {\n return processValue(0, config);\n }\n return processValue(priceTimesShares.dividedBy(totalShares), config);\n};\n"]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export type { IBigNumber, IBigNumberFormat, IBigNumberRoundingMode, IBigNumberRoundingModeName, IBigNumberToType, IBigNumberValue, IConfig, IOutput, IType, } from './shared/types.js';
|
|
2
|
+
export { BigNumber } from './shared/constants.js';
|
|
3
|
+
export { ERRORS } from './shared/errors.js';
|
|
4
|
+
export { getBigNumber, isBigNumber, isFloat, isInteger, isNumber, prettifyValue, processValue, } from './processing/processing.js';
|
|
5
|
+
export { adjustByPercentage, calculateExchange, calculateExchangeFee, calculateMax, calculateMean, calculateMedian, calculateMin, calculatePercentageChange, calculatePercentageRepresentation, calculateSum, calculateWeightedEntry, } from './calculations/calculations.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// constructor
|
|
2
|
+
export { BigNumber } from './shared/constants.js';
|
|
3
|
+
// error codes
|
|
4
|
+
export { ERRORS } from './shared/errors.js';
|
|
5
|
+
// value processors and type checks
|
|
6
|
+
export { getBigNumber, isBigNumber, isFloat, isInteger, isNumber, prettifyValue, processValue, } from './processing/processing.js';
|
|
7
|
+
// calculations
|
|
8
|
+
export { adjustByPercentage, calculateExchange, calculateExchangeFee, calculateMax, calculateMean, calculateMedian, calculateMin, calculatePercentageChange, calculatePercentageRepresentation, calculateSum, calculateWeightedEntry, } from './calculations/calculations.js';
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAaA,cAAc;AACd,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD,cAAc;AACd,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE5C,mCAAmC;AACnC,OAAO,EACL,YAAY,EACZ,WAAW,EACX,OAAO,EACP,SAAS,EACT,QAAQ,EACR,aAAa,EACb,YAAY,GACb,MAAM,4BAA4B,CAAC;AAEpC,eAAe;AACf,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,oBAAoB,EACpB,YAAY,EACZ,aAAa,EACb,eAAe,EACf,YAAY,EACZ,yBAAyB,EACzB,iCAAiC,EACjC,YAAY,EACZ,sBAAsB,GACvB,MAAM,gCAAgC,CAAC","sourcesContent":["// types\nexport type {\n IBigNumber,\n IBigNumberFormat,\n IBigNumberRoundingMode,\n IBigNumberRoundingModeName,\n IBigNumberToType,\n IBigNumberValue,\n IConfig,\n IOutput,\n IType,\n} from './shared/types.js';\n\n// constructor\nexport { BigNumber } from './shared/constants.js';\n\n// error codes\nexport { ERRORS } from './shared/errors.js';\n\n// value processors and type checks\nexport {\n getBigNumber,\n isBigNumber,\n isFloat,\n isInteger,\n isNumber,\n prettifyValue,\n processValue,\n} from './processing/processing.js';\n\n// calculations\nexport {\n adjustByPercentage,\n calculateExchange,\n calculateExchangeFee,\n calculateMax,\n calculateMean,\n calculateMedian,\n calculateMin,\n calculatePercentageChange,\n calculatePercentageRepresentation,\n calculateSum,\n calculateWeightedEntry,\n} from './calculations/calculations.js';\n"]}
|