adding par methods, benchmarks, github publishing
This commit is contained in:
parent
6fbfee180f
commit
2628571717
.gitea/workflows
.github/workflows
Cargo.lockCargo.tomlFinLib.NET/FinLib
README.mdfinlib
@ -97,6 +97,7 @@ jobs:
|
||||
name: Publish .NET
|
||||
runs-on: ubuntu-latest
|
||||
needs: [ buildNET ] # for ignoring bad builds
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
@ -124,11 +125,11 @@ jobs:
|
||||
|
||||
- name: Pack
|
||||
working-directory: ./FinLib.NET/FinLib
|
||||
run: dotnet pack
|
||||
run: dotnet pack -p:PackageVersion=$(pushd ../../finlib > /dev/null && cargo pkgid | awk -F '[,#]' '{print $2}' && popd > /dev/null)
|
||||
|
||||
- name: Push
|
||||
working-directory: ./FinLib.NET/FinLib
|
||||
run: dotnet nuget push ./bin/Release/FinLib.NET.0.0.5.nupkg --api-key ${{ secrets.DOCKERHUB_TOKEN }} --source https://gitea.sheep-ghoul.ts.net/api/packages/sarsoo/nuget/index.json
|
||||
run: dotnet nuget push ./bin/Release/FinLib.NET.$(pushd ../../finlib > /dev/null && cargo pkgid | awk -F '[,#]' '{print $2}' && popd > /dev/null).nupkg --api-key ${{ secrets.DOCKERHUB_TOKEN }} --source https://gitea.sheep-ghoul.ts.net/api/packages/sarsoo/nuget/index.json
|
||||
|
||||
buildWASM:
|
||||
name: Build WASM
|
||||
|
69
.github/workflows/build.yml
vendored
69
.github/workflows/build.yml
vendored
@ -99,6 +99,42 @@ jobs:
|
||||
working-directory: ./FinLib.NET
|
||||
run: dotnet test --no-restore
|
||||
|
||||
publishNET:
|
||||
name: Publish .NET
|
||||
runs-on: ubuntu-latest
|
||||
needs: [ buildNET ] # for ignoring bad builds
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install Rust
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
|
||||
- name: Cargo Build
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
|
||||
- name: Setup .NET Core SDK 9.0.x
|
||||
uses: actions/setup-dotnet@v3.0.3
|
||||
with:
|
||||
dotnet-version: 9.0.x
|
||||
|
||||
- name: Install Dependencies
|
||||
working-directory: ./FinLib.NET
|
||||
run: dotnet restore
|
||||
|
||||
- name: Pack
|
||||
working-directory: ./FinLib.NET/FinLib
|
||||
run: dotnet pack -p:PackageVersion=$(pushd ../../finlib > /dev/null && cargo pkgid | awk -F '[,#]' '{print $2}' && popd > /dev/null) -P:PackageId="Sarsoo.FinLib.NET"
|
||||
|
||||
- name: Push
|
||||
working-directory: ./FinLib.NET/FinLib
|
||||
run: dotnet nuget push ./bin/Release/Sarsoo.FinLib.NET.$(pushd ../../finlib > /dev/null && cargo pkgid | awk -F '[,#]' '{print $2}' && popd > /dev/null).nupkg --api-key ${{ secrets.NUGET_TOKEN }} --source https://api.nuget.org/v3/index.json
|
||||
|
||||
buildWASM:
|
||||
name: Build WASM
|
||||
runs-on: ubuntu-latest
|
||||
@ -125,7 +161,7 @@ jobs:
|
||||
name: github-pages
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
runs-on: ubuntu-latest
|
||||
needs: [ build, buildPy, buildWASM ] # for ignoring bad builds
|
||||
needs: [ build, buildPy, buildWASM, buildNET ] # for ignoring bad builds
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
|
||||
steps:
|
||||
- name: Checkout
|
||||
@ -228,4 +264,33 @@ jobs:
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: publish
|
||||
args: --package finlib
|
||||
args: --package finlib
|
||||
|
||||
publishPy:
|
||||
runs-on: ubuntu-latest
|
||||
name: Publish Python Library
|
||||
needs: [ buildPy ] # for ignoring bad builds
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install Rust
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
|
||||
- name: Install Python 3
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: ${{ env.python-version }}
|
||||
|
||||
- name: Install Maturin
|
||||
working-directory: ./pyfinlib
|
||||
run: python3 -m venv .venv && source .venv/bin/activate && pip3 install -r requirements.txt
|
||||
|
||||
- name: Publish
|
||||
working-directory: ./pyfinlib
|
||||
run: source .venv/bin/activate && maturin publish
|
||||
env:
|
||||
MATURIN_PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }}
|
173
Cargo.lock
generated
173
Cargo.lock
generated
@ -11,6 +11,12 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anes"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.6.18"
|
||||
@ -106,6 +112,12 @@ version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||
|
||||
[[package]]
|
||||
name = "cast"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
|
||||
|
||||
[[package]]
|
||||
name = "cbindgen"
|
||||
version = "0.28.0"
|
||||
@ -140,6 +152,33 @@ version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "ciborium"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e"
|
||||
dependencies = [
|
||||
"ciborium-io",
|
||||
"ciborium-ll",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ciborium-io"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757"
|
||||
|
||||
[[package]]
|
||||
name = "ciborium-ll"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9"
|
||||
dependencies = [
|
||||
"ciborium-io",
|
||||
"half",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.29"
|
||||
@ -194,6 +233,42 @@ dependencies = [
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "criterion"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f"
|
||||
dependencies = [
|
||||
"anes",
|
||||
"cast",
|
||||
"ciborium",
|
||||
"clap",
|
||||
"criterion-plot",
|
||||
"is-terminal",
|
||||
"itertools 0.10.5",
|
||||
"num-traits",
|
||||
"once_cell",
|
||||
"oorandom",
|
||||
"plotters",
|
||||
"rayon",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"tinytemplate",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "criterion-plot"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1"
|
||||
dependencies = [
|
||||
"cast",
|
||||
"itertools 0.10.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.8.6"
|
||||
@ -219,6 +294,12 @@ version = "0.8.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
|
||||
|
||||
[[package]]
|
||||
name = "crunchy"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929"
|
||||
|
||||
[[package]]
|
||||
name = "csbindgen"
|
||||
version = "1.9.3"
|
||||
@ -259,14 +340,16 @@ checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
|
||||
|
||||
[[package]]
|
||||
name = "finlib"
|
||||
version = "0.0.5"
|
||||
version = "0.0.6"
|
||||
dependencies = [
|
||||
"criterion",
|
||||
"getrandom 0.2.15",
|
||||
"log",
|
||||
"nalgebra",
|
||||
"ndarray",
|
||||
"ndarray-stats",
|
||||
"pyo3",
|
||||
"rand",
|
||||
"rayon",
|
||||
"statrs",
|
||||
"wasm-bindgen",
|
||||
@ -274,7 +357,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "finlib-ffi"
|
||||
version = "0.0.5"
|
||||
version = "0.0.6"
|
||||
dependencies = [
|
||||
"cbindgen",
|
||||
"csbindgen",
|
||||
@ -283,7 +366,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "finlib-wasm"
|
||||
version = "0.0.5"
|
||||
version = "0.0.6"
|
||||
dependencies = [
|
||||
"console_error_panic_hook",
|
||||
"console_log",
|
||||
@ -318,6 +401,16 @@ dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "half"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crunchy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.15.2"
|
||||
@ -336,6 +429,12 @@ version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc"
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.7.1"
|
||||
@ -352,12 +451,32 @@ version = "2.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5"
|
||||
|
||||
[[package]]
|
||||
name = "is-terminal"
|
||||
version = "0.4.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e19b23d53f35ce9f56aebc7d1bb4e6ac1e9c0db7ac85c8d1760c04379edced37"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is_terminal_polyfill"
|
||||
version = "1.70.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.10.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.13.0"
|
||||
@ -493,7 +612,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "17ebbe97acce52d06aebed4cd4a87c0941f4b2519b59b82b4feb5bd0ce003dfd"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"itertools",
|
||||
"itertools 0.13.0",
|
||||
"ndarray",
|
||||
"noisy_float",
|
||||
"num-integer",
|
||||
@ -565,12 +684,46 @@ version = "1.20.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e"
|
||||
|
||||
[[package]]
|
||||
name = "oorandom"
|
||||
version = "11.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9"
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
||||
|
||||
[[package]]
|
||||
name = "plotters"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
"plotters-backend",
|
||||
"plotters-svg",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "plotters-backend"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a"
|
||||
|
||||
[[package]]
|
||||
name = "plotters-svg"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670"
|
||||
dependencies = [
|
||||
"plotters-backend",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic"
|
||||
version = "1.10.0"
|
||||
@ -606,7 +759,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pyfinlib"
|
||||
version = "0.0.5"
|
||||
version = "0.0.6"
|
||||
dependencies = [
|
||||
"finlib",
|
||||
"log",
|
||||
@ -944,6 +1097,16 @@ dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinytemplate"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.8.20"
|
||||
|
@ -14,7 +14,7 @@ default-members = [
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.0.5"
|
||||
version = "0.0.6"
|
||||
authors = ["sarsoo <andy@sarsoo.xyz>"]
|
||||
description = "Quant finance functions implemented in Rust"
|
||||
edition = "2021"
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<PackageId>FinLib.NET</PackageId>
|
||||
<Version>0.0.5</Version>
|
||||
<Authors>sarsoo</Authors>
|
||||
</PropertyGroup>
|
||||
|
||||
|
42
README.md
42
README.md
@ -1,18 +1,54 @@
|
||||
# finlib
|
||||
|
||||
[](https://github.com/Sarsoo/finlib/actions/workflows/build.yml)
|
||||
|
||||
Some quantitative finance functionality written in Rust and consumable from many higher-level languages.
|
||||
|
||||
## Derivatives Pricing
|
||||
- Options
|
||||
- Black-Scholes
|
||||
- Prices
|
||||
- Greeks
|
||||
|
||||
## Risk
|
||||
- Value-at-Risk
|
||||
- Historical
|
||||
- Variance-Covariance (Parametric)
|
||||
- Single Asset
|
||||
- Portfolio
|
||||
|
||||
# FFI
|
||||
|
||||
## Python
|
||||
- C++
|
||||
- FFI header files for C++ are generated automatically during build by [cbindgen](https://github.com/mozilla/cbindgen).
|
||||
- .NET
|
||||
- FFI wrapper code for C# tareting .NET Standard 2.0 is generated automatically using [csbindgen](https://github.com/Cysharp/csbindgen/).
|
||||
- Python
|
||||
- An adapter library for Python is generated usign [PyO3](https://github.com/PyO3/pyo3)
|
||||
- WASM (Js)
|
||||
- A Javascript library is generated using [wasm-bindgen](https://github.com/rustwasm/wasm-bindgen)
|
||||
|
||||
## [.NET](./finlib-ffi)
|
||||
|
||||
```bash
|
||||
cargo build
|
||||
cd FinLib.NET
|
||||
dotnet build
|
||||
```
|
||||
|
||||
## [Python](./pyfinlib)
|
||||
|
||||
```bash
|
||||
cd pyfinlib
|
||||
python -m venv .venv
|
||||
source .venv/bin/activate
|
||||
pip install -r requirements.txt
|
||||
maturin develop
|
||||
```
|
||||
|
||||
## WASM
|
||||
## [WASM](finlib-wasm)
|
||||
|
||||
```
|
||||
```bash
|
||||
cd finlib-wasm
|
||||
wasm-pack build
|
||||
```
|
@ -13,16 +13,27 @@ license.workspace = true
|
||||
[dependencies]
|
||||
wasm-bindgen = { workspace = true, optional = true }
|
||||
pyo3 = { workspace = true, optional = true }
|
||||
rayon = { workspace = true, optional = true }
|
||||
rayon = { workspace = true }
|
||||
ndarray = { workspace = true }
|
||||
ndarray-stats = { workspace = true }
|
||||
nalgebra = { workspace = true }
|
||||
statrs = { workspace = true }
|
||||
log = { workspace = true }
|
||||
getrandom = "~0"
|
||||
rand = "0.8.5"
|
||||
|
||||
[dev-dependencies]
|
||||
criterion = "0.5.1"
|
||||
|
||||
[[bench]]
|
||||
name = "rayon_roc"
|
||||
harness = false
|
||||
|
||||
[[bench]]
|
||||
name = "rayon_options"
|
||||
harness = false
|
||||
|
||||
[features]
|
||||
py = ["dep:pyo3"]
|
||||
wasm = ["getrandom/js", "dep:wasm-bindgen"]
|
||||
parallel = ["dep:rayon"]
|
||||
ffi = []
|
43
finlib/benches/rayon_options.rs
Normal file
43
finlib/benches/rayon_options.rs
Normal file
@ -0,0 +1,43 @@
|
||||
use criterion::{criterion_group, criterion_main, AxisScale, BatchSize, BenchmarkId, Criterion, PlotConfiguration, Throughput};
|
||||
use finlib::options::blackscholes::option_surface::OptionSurface;
|
||||
use finlib::options::blackscholes::{generate_options, par_generate_options};
|
||||
|
||||
pub fn bench_generate_options(c: &mut Criterion) {
|
||||
let mut group = c.benchmark_group("Options::generate_options");
|
||||
|
||||
let plot_config = PlotConfiguration::default()
|
||||
.summary_scale(AxisScale::Logarithmic);
|
||||
group.plot_config(plot_config);
|
||||
|
||||
for i in [1, 10, 100, 1000].into_iter() {
|
||||
|
||||
let surface = OptionSurface::from(
|
||||
0 .. 10,
|
||||
(100., 200.),
|
||||
0 .. i,
|
||||
(100., 200.),
|
||||
0 .. 5,
|
||||
(0.25, 0.50),
|
||||
0 .. 10,
|
||||
(0.05, 0.08),
|
||||
0 .. 1,
|
||||
(0.01, 0.02),
|
||||
0 .. 10,
|
||||
(30./365.25, 30./365.25),
|
||||
);
|
||||
|
||||
let variables = surface.walk();
|
||||
|
||||
group.throughput(Throughput::Elements(variables.len() as u64));
|
||||
group.bench_function(BenchmarkId::new("Sequential", variables.len()), |b| {
|
||||
b.iter_batched(|| variables.clone(), |p| { generate_options(&p); }, BatchSize::SmallInput)
|
||||
});
|
||||
group.bench_function(BenchmarkId::new("Parallel", variables.len()), |b| {
|
||||
b.iter_batched(|| variables.clone(), |p| { par_generate_options(&p); }, BatchSize::SmallInput)
|
||||
});
|
||||
}
|
||||
group.finish();
|
||||
}
|
||||
|
||||
criterion_group!(benches, bench_generate_options);
|
||||
criterion_main!(benches);
|
65
finlib/benches/rayon_roc.rs
Normal file
65
finlib/benches/rayon_roc.rs
Normal file
@ -0,0 +1,65 @@
|
||||
use criterion::{criterion_group, criterion_main, AxisScale, BatchSize, BenchmarkId, Criterion, PlotConfiguration, Throughput};
|
||||
use finlib::risk::portfolio::{Portfolio, PortfolioAsset};
|
||||
use rand::Rng;
|
||||
|
||||
pub fn bench_apply_rates_of_change_values(c: &mut Criterion) {
|
||||
let mut group = c.benchmark_group("Portfolio::apply_rates_of_change/values");
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
let plot_config = PlotConfiguration::default()
|
||||
.summary_scale(AxisScale::Logarithmic);
|
||||
group.plot_config(plot_config);
|
||||
|
||||
for i in [10, 100, 1000, 10_000, 100_000, 1_000_000].into_iter() {
|
||||
|
||||
let portfolio = Portfolio::from(vec![
|
||||
PortfolioAsset::new(0.1, "a".to_string(), (0 .. i).map(|_| rng.gen::<f64>()).collect()),
|
||||
PortfolioAsset::new(0.1, "a".to_string(), (0 .. i).map(|_| rng.gen::<f64>()).collect()),
|
||||
PortfolioAsset::new(0.1, "a".to_string(), (0 .. i).map(|_| rng.gen::<f64>()).collect()),
|
||||
PortfolioAsset::new(0.1, "a".to_string(), (0 .. i).map(|_| rng.gen::<f64>()).collect()),
|
||||
PortfolioAsset::new(0.1, "a".to_string(), (0 .. i).map(|_| rng.gen::<f64>()).collect()),
|
||||
PortfolioAsset::new(0.1, "a".to_string(), (0 .. i).map(|_| rng.gen::<f64>()).collect()),
|
||||
PortfolioAsset::new(0.1, "a".to_string(), (0 .. i).map(|_| rng.gen::<f64>()).collect()),
|
||||
PortfolioAsset::new(0.1, "a".to_string(), (0 .. i).map(|_| rng.gen::<f64>()).collect()),
|
||||
PortfolioAsset::new(0.1, "a".to_string(), (0 .. i).map(|_| rng.gen::<f64>()).collect()),
|
||||
PortfolioAsset::new(0.1, "a".to_string(), (0 .. i).map(|_| rng.gen::<f64>()).collect())
|
||||
]);
|
||||
|
||||
group.throughput(Throughput::Elements((i * 10) as u64));
|
||||
group.bench_function(BenchmarkId::new("Sequential", i), |b| {
|
||||
b.iter_batched(|| portfolio.clone(), |mut p| { p.apply_rates_of_change(); }, BatchSize::SmallInput)
|
||||
});
|
||||
group.bench_function(BenchmarkId::new("Parallel", i), |b| {
|
||||
b.iter_batched(|| portfolio.clone(), |mut p| { p.par_apply_rates_of_change(); }, BatchSize::SmallInput)
|
||||
});
|
||||
}
|
||||
group.finish();
|
||||
}
|
||||
|
||||
pub fn bench_apply_rates_of_change_assets(c: &mut Criterion) {
|
||||
let mut group = c.benchmark_group("Portfolio::apply_rates_of_change/assets");
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
let plot_config = PlotConfiguration::default()
|
||||
.summary_scale(AxisScale::Logarithmic);
|
||||
group.plot_config(plot_config);
|
||||
|
||||
for i in [10, 100, 1000, 10_000].into_iter() {
|
||||
|
||||
let portfolio = Portfolio::from((0 .. i).map(|_| {
|
||||
PortfolioAsset::new(0.1, "a".to_string(), (0 .. 10000).map(|_| rng.gen::<f64>()).collect())
|
||||
}).collect());
|
||||
|
||||
group.throughput(Throughput::Elements(i as u64));
|
||||
group.bench_function(BenchmarkId::new("Sequential", i), |b| {
|
||||
b.iter_batched(|| portfolio.clone(), |mut p| { p.apply_rates_of_change(); }, BatchSize::SmallInput)
|
||||
});
|
||||
group.bench_function(BenchmarkId::new("Parallel", i), |b| {
|
||||
b.iter_batched(|| portfolio.clone(), |mut p| { p.par_apply_rates_of_change(); }, BatchSize::SmallInput)
|
||||
});
|
||||
}
|
||||
group.finish();
|
||||
}
|
||||
|
||||
criterion_group!(benches, bench_apply_rates_of_change_values, bench_apply_rates_of_change_assets);
|
||||
criterion_main!(benches);
|
@ -5,30 +5,4 @@ pub mod stats;
|
||||
pub mod util;
|
||||
pub mod risk;
|
||||
pub mod ffi;
|
||||
pub mod options;
|
||||
|
||||
#[cfg(feature = "parallel")]
|
||||
use rayon::prelude::*;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! gated_iter {
|
||||
($x:expr) => {
|
||||
{
|
||||
$x.iter()
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! gated_iter_mut {
|
||||
($x:expr) => {
|
||||
{
|
||||
if cfg!(feature = "parallel") {
|
||||
$x.par_iter_mut()
|
||||
}
|
||||
else {
|
||||
$x.iter_mut()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
pub mod options;
|
@ -1,174 +0,0 @@
|
||||
use core::ops::Range;
|
||||
use std::sync::{Arc, Mutex};
|
||||
#[cfg(feature = "parallel")]
|
||||
use rayon::prelude::*;
|
||||
use crate::options::blackscholes::OptionVariables;
|
||||
|
||||
pub struct OptionSurface {
|
||||
underlying_price: Range<isize>,
|
||||
underlying_price_bounds: (f64, f64),
|
||||
strike_price: Range<isize>,
|
||||
strike_price_bounds: (f64, f64),
|
||||
volatility: Range<isize>,
|
||||
volatility_bounds: (f64, f64),
|
||||
risk_free_interest_rate: Range<isize>,
|
||||
risk_free_interest_rate_bounds: (f64, f64),
|
||||
dividend: Range<isize>,
|
||||
dividend_bounds: (f64, f64),
|
||||
time_to_expiration: Range<isize>,
|
||||
time_to_expiration_bounds: (f64, f64)
|
||||
}
|
||||
|
||||
impl OptionSurface {
|
||||
pub fn from(underlying_price: Range<isize>,
|
||||
underlying_price_bounds: (f64, f64),
|
||||
strike_price: Range<isize>,
|
||||
strike_price_bounds: (f64, f64),
|
||||
volatility: Range<isize>,
|
||||
volatility_bounds: (f64, f64),
|
||||
risk_free_interest_rate: Range<isize>,
|
||||
risk_free_interest_rate_bounds: (f64, f64),
|
||||
dividend: Range<isize>,
|
||||
dividend_bounds: (f64, f64),
|
||||
time_to_expiration: Range<isize>,
|
||||
time_to_expiration_bounds: (f64, f64)) -> Self {
|
||||
Self {
|
||||
underlying_price,
|
||||
underlying_price_bounds,
|
||||
strike_price,
|
||||
strike_price_bounds,
|
||||
volatility,
|
||||
volatility_bounds,
|
||||
risk_free_interest_rate,
|
||||
risk_free_interest_rate_bounds,
|
||||
dividend,
|
||||
dividend_bounds,
|
||||
time_to_expiration,
|
||||
time_to_expiration_bounds,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn walk(self) -> Vec<OptionVariables> {
|
||||
|
||||
// #[cfg(feature = "parallel")]
|
||||
// {
|
||||
// let vec: Arc<Mutex<Vec<OptionVariables>>> = Arc::new(Mutex::new(vec![]));
|
||||
// self.underlying_price
|
||||
// .into_par_iter()
|
||||
// .for_each(|p| {
|
||||
// self.strike_price
|
||||
// .clone()
|
||||
// .into_par_iter()
|
||||
// .for_each(|s| {
|
||||
// self.volatility
|
||||
// .clone()
|
||||
// .into_par_iter()
|
||||
// .for_each(|v| {
|
||||
// self.risk_free_interest_rate
|
||||
// .clone()
|
||||
// .into_par_iter()
|
||||
// .for_each(|i| {
|
||||
// self.dividend
|
||||
// .clone()
|
||||
// .into_par_iter()
|
||||
// .for_each(|d| {
|
||||
// self.time_to_expiration
|
||||
// .clone()
|
||||
// .into_par_iter()
|
||||
// .for_each(|t| {
|
||||
// let mut m = vec.clone();
|
||||
// let mut guard = m.lock().unwrap();
|
||||
// guard.push(OptionVariables::from(
|
||||
// self.underlying_price_bounds.0 + (self.underlying_price_bounds.1 - self.underlying_price_bounds.0) * p as f64,
|
||||
// self.strike_price_bounds.0 + (self.strike_price_bounds.1 - self.strike_price_bounds.0) * s as f64,
|
||||
// self.volatility_bounds.0 + (self.volatility_bounds.1 - self.volatility_bounds.0) * v as f64,
|
||||
// self.risk_free_interest_rate_bounds.0 + (self.risk_free_interest_rate_bounds.1 - self.risk_free_interest_rate_bounds.0) * i as f64,
|
||||
// self.dividend_bounds.0 + (self.dividend_bounds.1 - self.dividend_bounds.0) * d as f64,
|
||||
// self.time_to_expiration_bounds.0 + (self.time_to_expiration_bounds.1 - self.time_to_expiration_bounds.0) * t as f64
|
||||
// ));
|
||||
// })
|
||||
// })
|
||||
// })
|
||||
// })
|
||||
// })
|
||||
// });
|
||||
//
|
||||
// Arc::try_unwrap(vec).unwrap().into_inner().unwrap()
|
||||
// }
|
||||
// #[cfg(not(feature = "parallel"))]
|
||||
{
|
||||
let mut vec: Vec<OptionVariables> = Vec::with_capacity(
|
||||
self.underlying_price.len()
|
||||
* self.strike_price.len()
|
||||
* self.volatility.len()
|
||||
* self.risk_free_interest_rate.len()
|
||||
* self.dividend.len()
|
||||
* self.time_to_expiration.len()
|
||||
);
|
||||
for p in self.underlying_price {
|
||||
for s in self.strike_price.clone() {
|
||||
for v in self.volatility.clone() {
|
||||
for i in self.risk_free_interest_rate.clone() {
|
||||
for d in self.dividend.clone() {
|
||||
for t in self.time_to_expiration.clone() {
|
||||
let v = OptionVariables::from(
|
||||
self.underlying_price_bounds.0 + (self.underlying_price_bounds.1 - self.underlying_price_bounds.0) * p as f64,
|
||||
self.strike_price_bounds.0 + (self.strike_price_bounds.1 - self.strike_price_bounds.0) * s as f64,
|
||||
self.volatility_bounds.0 + (self.volatility_bounds.1 - self.volatility_bounds.0) * v as f64,
|
||||
self.risk_free_interest_rate_bounds.0 + (self.risk_free_interest_rate_bounds.1 - self.risk_free_interest_rate_bounds.0) * i as f64,
|
||||
self.dividend_bounds.0 + (self.dividend_bounds.1 - self.dividend_bounds.0) * d as f64,
|
||||
self.time_to_expiration_bounds.0 + (self.time_to_expiration_bounds.1 - self.time_to_expiration_bounds.0) * t as f64
|
||||
);
|
||||
vec.push(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vec
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::options::blackscholes::{CallOption, Option, PutOption};
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn walk_test() {
|
||||
let w = OptionSurface::from(
|
||||
(0 .. 50),
|
||||
(100., 200.),
|
||||
(0 .. 50),
|
||||
(100., 200.),
|
||||
(0 .. 5),
|
||||
(0.25, 0.50),
|
||||
(0 .. 10),
|
||||
(0.05, 0.08),
|
||||
(0 .. 1),
|
||||
(0.01, 0.02),
|
||||
(0 .. 10),
|
||||
(30./365.25, 30./365.25),
|
||||
);
|
||||
|
||||
let a = w.walk();
|
||||
|
||||
let options = a
|
||||
.iter()
|
||||
.map(|v| {
|
||||
let mut call = v.call();
|
||||
let mut put = v.put();
|
||||
|
||||
call.calc_greeks();
|
||||
put.calc_greeks();
|
||||
|
||||
(call, put)
|
||||
})
|
||||
.collect::<Vec<(CallOption, PutOption)>>();
|
||||
|
||||
let a1 = a.first();
|
||||
}
|
||||
}
|
32
finlib/src/options/blackscholes/generate.rs
Normal file
32
finlib/src/options/blackscholes/generate.rs
Normal file
@ -0,0 +1,32 @@
|
||||
use rayon::prelude::*;
|
||||
use crate::options::blackscholes::{CallOption, Option, OptionVariables, PutOption};
|
||||
|
||||
pub fn generate_options(option_variables: &Vec<OptionVariables>) -> Vec<(CallOption, PutOption)> {
|
||||
option_variables
|
||||
.iter()
|
||||
.map(|v| {
|
||||
let mut call = v.call();
|
||||
let mut put = v.put();
|
||||
|
||||
call.calc_greeks();
|
||||
put.calc_greeks();
|
||||
|
||||
(call, put)
|
||||
})
|
||||
.collect::<Vec<(CallOption, PutOption)>>()
|
||||
}
|
||||
|
||||
pub fn par_generate_options(option_variables: &Vec<OptionVariables>) -> Vec<(CallOption, PutOption)> {
|
||||
option_variables
|
||||
.par_iter()
|
||||
.map(|v| {
|
||||
let mut call = v.call();
|
||||
let mut put = v.put();
|
||||
|
||||
call.calc_greeks();
|
||||
put.calc_greeks();
|
||||
|
||||
(call, put)
|
||||
})
|
||||
.collect::<Vec<(CallOption, PutOption)>>()
|
||||
}
|
@ -1,4 +1,6 @@
|
||||
mod OptionSurface;
|
||||
pub mod option_surface;
|
||||
pub mod generate;
|
||||
pub use generate::*;
|
||||
|
||||
use statrs::distribution::{Continuous, ContinuousCDF, Normal};
|
||||
#[cfg(feature = "wasm")]
|
||||
|
113
finlib/src/options/blackscholes/option_surface.rs
Normal file
113
finlib/src/options/blackscholes/option_surface.rs
Normal file
@ -0,0 +1,113 @@
|
||||
use core::ops::Range;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use crate::options::blackscholes::{CallOption, Option, OptionVariables, PutOption};
|
||||
|
||||
pub struct OptionSurface {
|
||||
underlying_price: Range<isize>,
|
||||
underlying_price_bounds: (f64, f64),
|
||||
strike_price: Range<isize>,
|
||||
strike_price_bounds: (f64, f64),
|
||||
volatility: Range<isize>,
|
||||
volatility_bounds: (f64, f64),
|
||||
risk_free_interest_rate: Range<isize>,
|
||||
risk_free_interest_rate_bounds: (f64, f64),
|
||||
dividend: Range<isize>,
|
||||
dividend_bounds: (f64, f64),
|
||||
time_to_expiration: Range<isize>,
|
||||
time_to_expiration_bounds: (f64, f64)
|
||||
}
|
||||
|
||||
impl OptionSurface {
|
||||
pub fn from(underlying_price: Range<isize>,
|
||||
underlying_price_bounds: (f64, f64),
|
||||
strike_price: Range<isize>,
|
||||
strike_price_bounds: (f64, f64),
|
||||
volatility: Range<isize>,
|
||||
volatility_bounds: (f64, f64),
|
||||
risk_free_interest_rate: Range<isize>,
|
||||
risk_free_interest_rate_bounds: (f64, f64),
|
||||
dividend: Range<isize>,
|
||||
dividend_bounds: (f64, f64),
|
||||
time_to_expiration: Range<isize>,
|
||||
time_to_expiration_bounds: (f64, f64)) -> Self {
|
||||
Self {
|
||||
underlying_price,
|
||||
underlying_price_bounds,
|
||||
strike_price,
|
||||
strike_price_bounds,
|
||||
volatility,
|
||||
volatility_bounds,
|
||||
risk_free_interest_rate,
|
||||
risk_free_interest_rate_bounds,
|
||||
dividend,
|
||||
dividend_bounds,
|
||||
time_to_expiration,
|
||||
time_to_expiration_bounds,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn walk(self) -> Vec<OptionVariables> {
|
||||
|
||||
let mut vec: Vec<OptionVariables> = Vec::with_capacity(
|
||||
self.underlying_price.len()
|
||||
* self.strike_price.len()
|
||||
* self.volatility.len()
|
||||
* self.risk_free_interest_rate.len()
|
||||
* self.dividend.len()
|
||||
* self.time_to_expiration.len()
|
||||
);
|
||||
for p in self.underlying_price {
|
||||
for s in self.strike_price.clone() {
|
||||
for v in self.volatility.clone() {
|
||||
for i in self.risk_free_interest_rate.clone() {
|
||||
for d in self.dividend.clone() {
|
||||
for t in self.time_to_expiration.clone() {
|
||||
let v = OptionVariables::from(
|
||||
self.underlying_price_bounds.0 + (self.underlying_price_bounds.1 - self.underlying_price_bounds.0) * p as f64,
|
||||
self.strike_price_bounds.0 + (self.strike_price_bounds.1 - self.strike_price_bounds.0) * s as f64,
|
||||
self.volatility_bounds.0 + (self.volatility_bounds.1 - self.volatility_bounds.0) * v as f64,
|
||||
self.risk_free_interest_rate_bounds.0 + (self.risk_free_interest_rate_bounds.1 - self.risk_free_interest_rate_bounds.0) * i as f64,
|
||||
self.dividend_bounds.0 + (self.dividend_bounds.1 - self.dividend_bounds.0) * d as f64,
|
||||
self.time_to_expiration_bounds.0 + (self.time_to_expiration_bounds.1 - self.time_to_expiration_bounds.0) * t as f64
|
||||
);
|
||||
vec.push(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vec
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::options::blackscholes::{generate_options, CallOption, Option, PutOption};
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn walk_test() {
|
||||
let w = OptionSurface::from(
|
||||
(0 .. 50),
|
||||
(100., 200.),
|
||||
(0 .. 50),
|
||||
(100., 200.),
|
||||
(0 .. 5),
|
||||
(0.25, 0.50),
|
||||
(0 .. 10),
|
||||
(0.05, 0.08),
|
||||
(0 .. 1),
|
||||
(0.01, 0.02),
|
||||
(0 .. 10),
|
||||
(30./365.25, 30./365.25),
|
||||
);
|
||||
|
||||
let a = w.walk();
|
||||
|
||||
let options = generate_options(&a);
|
||||
|
||||
let a1 = a.first();
|
||||
}
|
||||
}
|
@ -5,7 +5,6 @@ use ndarray_stats::CorrelationExt;
|
||||
use wasm_bindgen::prelude::*;
|
||||
#[cfg(feature = "py")]
|
||||
use pyo3::prelude::*;
|
||||
#[cfg(feature = "parallel")]
|
||||
use rayon::prelude::*;
|
||||
use statrs::distribution::{ContinuousCDF, Normal};
|
||||
use crate::risk::forecast::{mean_investment, std_dev_investment};
|
||||
@ -96,18 +95,16 @@ impl Portfolio {
|
||||
|
||||
/// Convert a portfolio of assets with absolute values to the percentage change in values
|
||||
pub fn apply_rates_of_change(&mut self) {
|
||||
#[cfg(feature = "parallel")]
|
||||
{
|
||||
self.assets.par_iter_mut().for_each(|asset| {
|
||||
asset.apply_rates_of_change();
|
||||
});
|
||||
}
|
||||
#[cfg(not(feature = "parallel"))]
|
||||
{
|
||||
self.assets.iter_mut().for_each(|asset| {
|
||||
asset.apply_rates_of_change();
|
||||
});
|
||||
}
|
||||
self.assets.iter_mut().for_each(|asset| {
|
||||
asset.apply_rates_of_change();
|
||||
});
|
||||
}
|
||||
|
||||
#[deprecated(note = "a lot slower than the sequential method, sans par prefix")]
|
||||
pub fn par_apply_rates_of_change(&mut self) {
|
||||
self.assets.par_iter_mut().for_each(|asset| {
|
||||
asset.apply_rates_of_change();
|
||||
});
|
||||
}
|
||||
|
||||
/// Do all the assets in the portfolio have the same number of values (required to perform matrix operations)
|
||||
@ -155,29 +152,33 @@ impl Portfolio {
|
||||
let column_count = self.assets.len();
|
||||
let row_count = self.assets[0].values.len();
|
||||
|
||||
#[cfg(feature = "parallel")]
|
||||
{
|
||||
let matrix = Array2::from_shape_vec((column_count, row_count),
|
||||
self.assets
|
||||
.par_iter()
|
||||
.map(|a| a.values.clone())
|
||||
.flatten()
|
||||
.collect::<Vec<f64>>()
|
||||
).unwrap();
|
||||
Some(matrix.into_owned())
|
||||
}
|
||||
#[cfg(not(feature = "parallel"))]
|
||||
{
|
||||
let matrix = Array2::from_shape_vec((column_count, row_count),
|
||||
self.assets
|
||||
.iter()
|
||||
.map(|a| a.values.clone())
|
||||
.flatten()
|
||||
.collect::<Vec<f64>>()
|
||||
).unwrap();
|
||||
Some(matrix.into_owned())
|
||||
let matrix = Array2::from_shape_vec((column_count, row_count),
|
||||
self.assets
|
||||
.iter()
|
||||
.map(|a| a.values.clone())
|
||||
.flatten()
|
||||
.collect::<Vec<f64>>()
|
||||
).unwrap();
|
||||
Some(matrix.into_owned())
|
||||
}
|
||||
|
||||
/// Format the asset values in the portfolio as a matrix such that statistical operations can be applied to it
|
||||
pub fn par_get_matrix(&self) -> Option<Array2<f64>> {
|
||||
if self.assets.is_empty() || !self.valid_sizes() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let column_count = self.assets.len();
|
||||
let row_count = self.assets[0].values.len();
|
||||
|
||||
let matrix = Array2::from_shape_vec((column_count, row_count),
|
||||
self.assets
|
||||
.par_iter()
|
||||
.map(|a| a.values.clone())
|
||||
.flatten()
|
||||
.collect::<Vec<f64>>()
|
||||
).unwrap();
|
||||
Some(matrix.into_owned())
|
||||
}
|
||||
|
||||
/// Calculate the mean and the standard deviation of a portfolio, taking into account the relative weights and covariance of the portfolio's assets
|
||||
|
@ -1,6 +1,4 @@
|
||||
use crate::util::roc::rates_of_change;
|
||||
|
||||
#[cfg(feature = "parallel")]
|
||||
use rayon::prelude::*;
|
||||
|
||||
// https://www.simtrade.fr/blog_simtrade/historical-method-var-calculation/
|
||||
@ -8,7 +6,6 @@ use rayon::prelude::*;
|
||||
pub fn value_at_risk(values: &[f64], confidence: f64) -> f64 {
|
||||
let mut roc = rates_of_change(values).collect::<Vec<_>>();
|
||||
|
||||
// roc.par_sort_by(|x, y| x.partial_cmp(y).unwrap());
|
||||
roc.sort_by(|x, y| x.partial_cmp(y).unwrap());
|
||||
|
||||
let threshold = (confidence * roc.len() as f64).floor() as usize;
|
||||
@ -16,6 +13,16 @@ pub fn value_at_risk(values: &[f64], confidence: f64) -> f64 {
|
||||
roc[threshold]
|
||||
}
|
||||
|
||||
pub fn par_value_at_risk(values: &[f64], confidence: f64) -> f64 {
|
||||
let mut roc = rates_of_change(values).collect::<Vec<_>>();
|
||||
|
||||
roc.par_sort_by(|x, y| x.partial_cmp(y).unwrap());
|
||||
|
||||
let threshold = (confidence * roc.len() as f64).floor() as usize;
|
||||
|
||||
roc[threshold]
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
@ -1,7 +1,6 @@
|
||||
use crate::stats;
|
||||
use crate::util::roc::rates_of_change;
|
||||
|
||||
#[cfg(feature = "parallel")]
|
||||
use rayon::prelude::*;
|
||||
use statrs::distribution::{ContinuousCDF, Normal};
|
||||
// https://medium.com/@serdarilarslan/value-at-risk-var-and-its-implementation-in-python-5c9150f73b0e
|
||||
|
@ -1,5 +1,3 @@
|
||||
#[cfg(feature = "parallel")]
|
||||
use rayon::prelude::*;
|
||||
use super::mean;
|
||||
|
||||
pub fn covariance(slice: &[f64], slice_two: &[f64]) -> Option<f64>
|
||||
@ -10,10 +8,8 @@ pub fn covariance(slice: &[f64], slice_two: &[f64]) -> Option<f64>
|
||||
let mean_2 = mean(slice_two);
|
||||
|
||||
Some(slice
|
||||
// .par_iter()
|
||||
.iter()
|
||||
.zip(slice_two
|
||||
// .par_iter()
|
||||
.iter()
|
||||
)
|
||||
.map(|(x, y)| (x - mean_1) * (y - mean_2))
|
||||
|
@ -1,17 +1,13 @@
|
||||
#[cfg(feature = "parallel")]
|
||||
use rayon::prelude::*;
|
||||
|
||||
pub fn changes(values: &[f64]) -> impl Iterator<Item = f64> + use<'_> {
|
||||
values
|
||||
.windows(2)
|
||||
// .par_windows(2)
|
||||
.map(|x| x[1] - x[0])
|
||||
}
|
||||
|
||||
pub fn rates_of_change(values: &[f64]) -> impl Iterator<Item = f64> + use<'_> {
|
||||
values
|
||||
.windows(2)
|
||||
// .par_windows(2)
|
||||
.map(|x| (x[1] - x[0])/x[0])
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user