-
Notifications
You must be signed in to change notification settings - Fork 0
[ENG-87] Implement price library #49
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Changes from all commits
Commits
Show all changes
47 commits
Select commit
Hold shift + click to select a range
4f572d4
[ENG-87] Implement price library
xbtmatt df427bb
Fix cargo.toml formatting
xbtmatt 56fc0f9
Fix checks, remove type assertions, check significand final result range
xbtmatt 81f13bf
Add todo/wip comment
xbtmatt 97b6f35
Add price changes with some stuff WIP
xbtmatt 5b87f04
Finish price implementation with reorganized files
xbtmatt 698041a
Add pinocchio to price deps so it's possible to use the `hint::` module
xbtmatt 36aeed1
Don't have doctests run the tests in macro docs
xbtmatt 0560ee4
Fix doctests instead of disabling them
xbtmatt cda4dbb
Fix constraints typo
xbtmatt a1dd93e
Use fallible decoded price conversions that factor in the possibility…
xbtmatt da88fb9
Updated mantissa range and add tests for it
xbtmatt 955c273
Add checks to the unbiased macro range checks
xbtmatt 7430b72
Make inner value of encoded price private
xbtmatt f3ef73f
Remove unnecessary qualification on bias in UNBIASED_* consts
xbtmatt 18f49cf
Make exponential 10^n const values in macro easier to read/evaluate f…
xbtmatt ce55456
Add const assertions and unit tests for the potential rebias overflow…
xbtmatt 2ffcb85
Add `get` documentation
xbtmatt bf7d13d
Fix underflow error variant name
xbtmatt 8465b6b
Add documentation for `as_exponent_and_mantissa`
xbtmatt 3b47ede
Add documentation for max biased exponent value and rename it and rem…
xbtmatt ebf2d85
Add a test that ensures the order info construction fails if the quot…
xbtmatt 2a8b15d
Update bitshift comment
xbtmatt 5abfbcd
Update decoded price documentation
xbtmatt 20e04fe
Remove `new_unchecked`
xbtmatt c2a87d7
Make mantissa constant bounds public
xbtmatt 749808d
Add documentation for `pow10_u64`
xbtmatt 534d218
Fix documentation being below attributes
xbtmatt fe7118f
Add `OrderInfo` documentation
xbtmatt 5261c36
Update const assertion to use `<=`, update documentation to reflect t…
xbtmatt 9a5680a
Update macro documentation to pass cargo test and be more descriptive
xbtmatt 2df1084
Add test for price mantissa * base scalar results in arithmetic overf…
xbtmatt 118c257
Add explicit exponent underflow unit test
xbtmatt d6c5f22
Use `matches` with the exact error type for `invalid_mantissas` unit …
xbtmatt 6df2336
Fix comment variable names
xbtmatt 5e881c4
Fix `price_bits` var naming, update to `mantissa_bits`
xbtmatt fa3308f
Clarify documentation on the exponent range; make formula for `UNBIAS…
xbtmatt 756077b
Make safety expectation on unchecked add with unit test condition che…
xbtmatt 24fcbad
Add `base_exponent_too_large` explicit unit test for `to_order_info`
xbtmatt 8ec535d
Derive `Copy` for validated mantissa
xbtmatt 44dd318
Fix `pow10_u64` macro formatting
xbtmatt 3f1e5cc
Make `EncodedPrice` repr transparent
xbtmatt 35f5b29
Remove trailing whitespace in macros.rs
xbtmatt 5a9db21
Remove trailing whitespace in other files
xbtmatt c9eae72
Fix `exponent` typo
xbtmatt b49a7bc
Add unit test for overflowing quote atoms
xbtmatt 1c059d1
Fix unclosed code blocks
xbtmatt File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| [package] | ||
| name = "price" | ||
| version.workspace = true | ||
| edition.workspace = true | ||
|
|
||
| [dependencies] | ||
| static_assertions.workspace = true | ||
| pinocchio.workspace = true | ||
|
|
||
| [dev-dependencies] | ||
| strum.workspace = true | ||
| strum_macros.workspace = true | ||
|
|
||
| [lints] | ||
| workspace = true |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| use crate::{ | ||
| EncodedPrice, | ||
| OrderInfoError, | ||
| ValidatedPriceMantissa, | ||
| BIAS, | ||
| ENCODED_PRICE_INFINITY, | ||
| ENCODED_PRICE_ZERO, | ||
| PRICE_MANTISSA_BITS, | ||
| PRICE_MANTISSA_MASK, | ||
| }; | ||
|
|
||
| /// An enum representing a decoded `EncodedPrice`. | ||
| #[derive(Clone)] | ||
| #[cfg_attr(test, derive(Debug))] | ||
| pub enum DecodedPrice { | ||
| Zero, | ||
| Infinity, | ||
| ExponentAndMantissa { | ||
| price_exponent_biased: u8, | ||
| price_mantissa: ValidatedPriceMantissa, | ||
| }, | ||
| } | ||
alnoki marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| impl DecodedPrice { | ||
| /// Return the optional tuple of exponent and mantissa from a decoded price. | ||
| /// If the decoded price is not a [`DecodedPrice::ExponentAndMantissa`], this returns `None`. | ||
| pub fn as_exponent_and_mantissa(&self) -> Option<(&u8, &ValidatedPriceMantissa)> { | ||
| if let DecodedPrice::ExponentAndMantissa { | ||
| price_exponent_biased, | ||
| price_mantissa, | ||
| } = self | ||
| { | ||
| Some((price_exponent_biased, price_mantissa)) | ||
| } else { | ||
| None | ||
xbtmatt marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
| } | ||
xbtmatt marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| impl TryFrom<EncodedPrice> for DecodedPrice { | ||
| type Error = OrderInfoError; | ||
|
|
||
| fn try_from(encoded: EncodedPrice) -> Result<Self, Self::Error> { | ||
| let res = match encoded.get() { | ||
| ENCODED_PRICE_ZERO => Self::Zero, | ||
| ENCODED_PRICE_INFINITY => Self::Infinity, | ||
| value => { | ||
| let price_exponent_biased = (value >> PRICE_MANTISSA_BITS) as u8; | ||
| let validated_mantissa = value & PRICE_MANTISSA_MASK; | ||
|
|
||
| Self::ExponentAndMantissa { | ||
| price_exponent_biased, | ||
| price_mantissa: ValidatedPriceMantissa::try_from(validated_mantissa)?, | ||
| } | ||
| } | ||
| }; | ||
|
|
||
| Ok(res) | ||
| } | ||
xbtmatt marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| impl TryFrom<DecodedPrice> for f64 { | ||
| type Error = OrderInfoError; | ||
|
|
||
| fn try_from(decoded: DecodedPrice) -> Result<Self, Self::Error> { | ||
| match decoded { | ||
| DecodedPrice::Zero => Ok(0f64), | ||
| DecodedPrice::Infinity => Err(OrderInfoError::InfinityIsNotAFloat), | ||
| DecodedPrice::ExponentAndMantissa { | ||
| price_exponent_biased, | ||
| price_mantissa, | ||
| } => { | ||
| let res = (price_mantissa.get() as f64) | ||
| * 10f64.powi(price_exponent_biased as i32 - BIAS as i32); | ||
| Ok(res) | ||
| } | ||
| } | ||
| } | ||
| } | ||
alnoki marked this conversation as resolved.
Show resolved
Hide resolved
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,102 @@ | ||
| use crate::{ | ||
| ValidatedPriceMantissa, | ||
| PRICE_MANTISSA_BITS, | ||
| }; | ||
|
|
||
| /// The encoded price as a u32. | ||
| /// | ||
| /// If `N` = the number of exponent bits and `M` = the number of price mantissa bits, the u32 bit | ||
| /// layout is: | ||
| /// | ||
| /// ```text | ||
| /// N M | ||
| /// |-------------------|-------------------| | ||
| /// [ exponent_bits ] | [ mantissa_bits ] | ||
| /// |---------------------------------------| | ||
| /// 32 | ||
| /// ``` | ||
alnoki marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| #[repr(transparent)] | ||
| #[derive(Copy, Clone, Debug)] | ||
| pub struct EncodedPrice(u32); | ||
|
|
||
| pub const ENCODED_PRICE_INFINITY: u32 = u32::MAX; | ||
| pub const ENCODED_PRICE_ZERO: u32 = 0; | ||
|
|
||
| impl EncodedPrice { | ||
| /// Creates a new [`EncodedPrice`] from a biased price exponent and a validated price mantissa. | ||
| #[inline(always)] | ||
| pub fn new(price_exponent_biased: u8, price_mantissa: ValidatedPriceMantissa) -> Self { | ||
| // The biased price exponent doesn't need to be checked because a leftwards bitshift will | ||
| // always discard irrelevant bits. | ||
| let exponent_bits = (price_exponent_biased as u32) << PRICE_MANTISSA_BITS; | ||
|
|
||
| // No need to mask the price mantissa since it has already been range checked/validated. | ||
| // Thus it's guaranteed it will only occupy the lower M bits where M = PRICE_MANTISSA_BITS. | ||
| Self(exponent_bits | price_mantissa.get()) | ||
| } | ||
xbtmatt marked this conversation as resolved.
Show resolved
Hide resolved
xbtmatt marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| /// Returns the inner encoded price as a u32. | ||
| #[inline(always)] | ||
| pub fn get(&self) -> u32 { | ||
| self.0 | ||
| } | ||
|
|
||
| /// The encoded price representation of a market buy/taker order with no constraints on the | ||
| /// maximum filled ask price. | ||
| #[inline(always)] | ||
| pub const fn infinity() -> Self { | ||
| Self(ENCODED_PRICE_INFINITY) | ||
| } | ||
|
|
||
| #[inline(always)] | ||
| pub fn is_infinity(&self) -> bool { | ||
| self.0 == ENCODED_PRICE_INFINITY | ||
| } | ||
|
|
||
| /// The encoded price representation of a market sell/taker order with no constraints on the | ||
| /// minimum filled bid price. | ||
| #[inline(always)] | ||
| pub const fn zero() -> Self { | ||
| Self(ENCODED_PRICE_ZERO) | ||
| } | ||
|
|
||
| #[inline(always)] | ||
| pub fn is_zero(&self) -> bool { | ||
| self.0 == ENCODED_PRICE_ZERO | ||
| } | ||
| } | ||
|
|
||
| #[cfg(test)] | ||
| mod tests { | ||
| use crate::{ | ||
| to_biased_exponent, | ||
| EncodedPrice, | ||
| ValidatedPriceMantissa, | ||
| BIAS, | ||
| PRICE_MANTISSA_BITS, | ||
| PRICE_MANTISSA_MASK, | ||
| }; | ||
|
|
||
| #[test] | ||
| fn encoded_price_mantissa_bits() { | ||
| let exponent = 0b0_1111; | ||
| let price_mantissa = 0b000_1111_0000_1111_0000_1111_0000; | ||
xbtmatt marked this conversation as resolved.
Show resolved
Hide resolved
xbtmatt marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| let encoded_price = EncodedPrice::new( | ||
| to_biased_exponent!(exponent), | ||
| ValidatedPriceMantissa::try_from(price_mantissa).unwrap(), | ||
| ); | ||
| assert_eq!( | ||
| encoded_price.0 >> PRICE_MANTISSA_BITS, | ||
| (exponent + BIAS) as u32 | ||
| ); | ||
| assert_eq!(encoded_price.0 & PRICE_MANTISSA_MASK, price_mantissa); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_infinity() { | ||
| assert_eq!(EncodedPrice::infinity().0, u32::MAX); | ||
| assert_eq!(EncodedPrice::zero().0, 0); | ||
| assert!(EncodedPrice::infinity().is_infinity()); | ||
| assert!(EncodedPrice::zero().is_zero()); | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| #[repr(u8)] | ||
| #[derive(Debug)] | ||
| #[cfg_attr(test, derive(strum_macros::Display))] | ||
| pub enum OrderInfoError { | ||
| ExponentUnderflow, | ||
| ArithmeticOverflow, | ||
| InvalidPriceMantissa, | ||
| InvalidBiasedExponent, | ||
xbtmatt marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| InfinityIsNotAFloat, | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.