diff --git a/Makefile b/Makefile index 7e0eb8b0045..1e6621283a6 100644 --- a/Makefile +++ b/Makefile @@ -99,16 +99,16 @@ cargo-test: echo "cargo-nextest is not installed. You can install it using 'cargo install cargo-nextest'"; \ exit 1; \ fi - RUST_BACKTRACE=1 && (cd nautilus_core && cargo nextest run --workspace --features "python,ffi,high-precision") + RUST_BACKTRACE=1 && (cd nautilus_core && cargo nextest run --workspace --features "python,ffi") -.PHONY: cargo-test-low-precision -cargo-test-low-precision: +.PHONY: cargo-test-high-precision +cargo-test-high-precision: @if ! cargo nextest --version >/dev/null 2>&1; then \ echo "cargo-nextest is not installed. You can install it using 'cargo install cargo-nextest'"; \ exit 1; \ fi - RUST_BACKTRACE=1 && (cd nautilus_core && cargo nextest run --workspace --features "python,ffi") + RUST_BACKTRACE=1 && (cd nautilus_core && cargo nextest run --workspace --features "python,ffi,high-precision") .PHONY: cargo-test-coverage diff --git a/README.md b/README.md index 7f7510046d0..ab53b45389f 100644 --- a/README.md +++ b/README.md @@ -173,6 +173,22 @@ We strive to document these changes in the release notes on a **best-effort basi We aim to follow a **weekly release schedule**, though experimental or larger features may cause delays. +## Precision mode + +NautilusTrader supports two precision modes for its core value types (`Price`, `Quantity`, `Money`), +which differ in their internal bit-width and maximum decimal precision. + +- **High-precision**: 128-bit integers with up to 16 decimals of precision, and a larger value range. +- **Standard-precision**: 64-bit integers with up to 9 decimals of precision, and a smaller value range. + +> [!NOTE] +> +> By default, the official Python wheels **ship** in high-precision (128-bit) mode on Linux and macOS. +> On Windows, only standard-precision (64-bit) is available due to the lack of native 128-bit integer support. +> For the Rust crates, the default is standard-precision unless you explicitly enable the `high-precision` feature flag. + +See the [Installation Guide](https://nautilustrader.io/docs/latest/getting_started/installation) for further details. + ## Installation ### From PyPI diff --git a/build.py b/build.py index c67882482db..fc5c515b906 100644 --- a/build.py +++ b/build.py @@ -48,7 +48,7 @@ if IS_WINDOWS and HIGH_PRECISION: print( "Warning: high-precision mode not supported on Windows (128-bit integers unavailable)\n" - "Forcing low-precision (64-bit) mode", + "Forcing standard-precision (64-bit) mode", ) HIGH_PRECISION = False diff --git a/docs/concepts/data.md b/docs/concepts/data.md index 5542137c03f..7808645b12e 100644 --- a/docs/concepts/data.md +++ b/docs/concepts/data.md @@ -383,11 +383,11 @@ Converts JSON back to Parquet format: The following migration examples both use trades data (you can also migrate the other data types in the same way). All commands should be run from the root of the `nautilus_core/persistence/` crate directory. -#### Migrating from low-precision (64-bit) to high-precision (128-bit) +#### Migrating from standard-precision (64-bit) to high-precision (128-bit) -This example describes a scenario where you want to migrate from low-precision schema data to high-precision schema data. +This example describes a scenario where you want to migrate from standard-precision schema data to high-precision schema data. -**1. Convert from low-precision Parquet to JSON**: +**1. Convert from standard-precision Parquet to JSON**: ```bash cargo run --bin to_json trades.parquet diff --git a/docs/concepts/overview.md b/docs/concepts/overview.md index 2ba81a170f3..5a53de04f46 100644 --- a/docs/concepts/overview.md +++ b/docs/concepts/overview.md @@ -228,7 +228,7 @@ When the `high-precision` feature flag is **enabled** (default), values use the | `Money` | `i128` | 16 | -17,014,118,346,046 | 17,014,118,346,046 | | `Quantity` | `u128` | 16 | 0 | 34,028,236,692,093 | -### Low-precision mode (64-bit) +### Standard-precision mode (64-bit) When the `high-precision` feature flag is **disabled**, values use the specification: diff --git a/docs/getting_started/installation.md b/docs/getting_started/installation.md index 029c4bf75fd..7ad04767423 100644 --- a/docs/getting_started/installation.md +++ b/docs/getting_started/installation.md @@ -206,17 +206,20 @@ We recommend using [Redis Insight](https://redis.io/insight/) as a GUI to visual ## Precision mode -NautilusTrader supports two precision modes which determine the bit-width of value types like `Price`, `Quantity`, and `Money`. +NautilusTrader supports two precision modes for its core value types (`Price`, `Quantity`, `Money`), +which differ in their internal bit-width and maximum decimal precision. -- **high-precision**: 128-bit integers with up to 16 decimals of precision, and a larger value range. -- **low-precision**: 64-bit integers with up to 9 decimals of precision, and a smaller value range. +- **High-precision**: 128-bit integers with up to 16 decimals of precision, and a larger value range. +- **Standard-precision**: 64-bit integers with up to 9 decimals of precision, and a smaller value range. :::note -High-precision mode is not available on Windows due to lack of 128-bit integer support in the Microsoft Visual C++ compiler. Windows users must use low-precision mode. +By default, the official Python wheels **ship** in high-precision (128-bit) mode on Linux and macOS. +On Windows, only standard-precision (64-bit) is available due to the lack of native 128-bit integer support. +For the Rust crates, the default is standard-precision unless you explicitly enable the `high-precision` feature flag. ::: -The tradeoff is slightly higher performance for low-precision (~3-5% for backtests), -but with a reduced maximum precision and value range. +The performance tradeoff is that standard-precision is ~3–5% faster in typical backtests, +but has lower decimal precision and a smaller representable value range. :::note Performance benchmarks comparing the modes are pending. @@ -224,10 +227,10 @@ Performance benchmarks comparing the modes are pending. ### Build configuration -The precision mode is controlled by: +The precision mode is determined by: -- The `HIGH_PRECISION` environment variable during compilation. -- The corresponding Rust feature flag `high-precision`. +- Setting the `HIGH_PRECISION` environment variable during compilation, **and/or** +- Enabling the `high-precision` Rust feature flag explicitly. #### High-precision mode (128-bit) @@ -236,7 +239,7 @@ export HIGH_PRECISION=true make install-debug ``` -#### Low-precision mode (64-bit) +#### Standard-precision mode (64-bit) ```bash export HIGH_PRECISION=false diff --git a/nautilus_core/model/src/types/fixed.rs b/nautilus_core/model/src/types/fixed.rs index 903f618fcd0..07276b5e49b 100644 --- a/nautilus_core/model/src/types/fixed.rs +++ b/nautilus_core/model/src/types/fixed.rs @@ -34,7 +34,7 @@ pub const FIXED_PRECISION: u8 = 9; #[no_mangle] pub static PRECISION_BYTES: i32 = 16; #[cfg(not(feature = "high-precision"))] -/// The width in bytes for fixed-point value types in low-precision mode (64-bit). +/// The width in bytes for fixed-point value types in standard-precision mode (64-bit). #[no_mangle] pub static PRECISION_BYTES: i32 = 8; @@ -45,7 +45,7 @@ pub const FIXED_SCALAR: f64 = 10_000_000_000_000_000.0; // 10.0**FIXED_PRECISION /// The scalar value corresponding to the maximum precision (10^9). pub const FIXED_SCALAR: f64 = 1_000_000_000.0; // 10.0**FIXED_PRECISION -/// The scalar representing the difference between high-precision and low-precision modes. +/// The scalar representing the difference between high-precision and standard-precision modes. pub const PRECISION_DIFF_SCALAR: f64 = 10_000_000.0; // 10.0**(16-9) /// Checks if a given `precision` value is within the allowed fixed-point precision range. diff --git a/nautilus_core/model/src/types/quantity.rs b/nautilus_core/model/src/types/quantity.rs index 7d2345bf975..480dbda786f 100644 --- a/nautilus_core/model/src/types/quantity.rs +++ b/nautilus_core/model/src/types/quantity.rs @@ -185,7 +185,7 @@ impl Quantity { self.raw / QuantityRaw::pow(10, u32::from(FIXED_PRECISION - self.precision)); // SAFETY: The raw value is guaranteed to be within i128 range after scaling // because our quantity constraints ensure the maximum raw value times the scaling - // factor cannot exceed i64::MAX (low-precision) or i128::MAX (high-precision). + // factor cannot exceed i128::MAX (high-precision) or i64::MAX (standard-precision). #[allow(clippy::useless_conversion)] // Required for precision modes Decimal::from_i128_with_scale(rescaled_raw as i128, u32::from(self.precision)) }