From d7e93502571bfed7c3b98f9f67fe33c2668922dc Mon Sep 17 00:00:00 2001 From: Nikolaos Karaolidis Date: Fri, 29 Mar 2024 13:40:49 +0000 Subject: [PATCH] Add initial ML implementation Signed-off-by: Nikolaos Karaolidis --- .gitlab-ci.yml | 8 +- Cargo.lock | 2601 +++++++++++++++++- Cargo.toml | 13 +- src/bin/qrust/threads/clock.rs | 19 +- src/bin/qrust/threads/data/mod.rs | 20 +- src/bin/qrust/threads/data/websocket/news.rs | 5 +- src/bin/trainer/mod.rs | 133 + src/lib/qrust/database/mod.rs | 1 + src/lib/qrust/database/ta.rs | 30 + src/lib/qrust/ml/batcher.rs | 74 + src/lib/qrust/ml/dataset.rs | 245 ++ src/lib/qrust/ml/mod.rs | 21 + src/lib/qrust/ml/model.rs | 160 ++ src/lib/qrust/mod.rs | 2 + src/lib/qrust/ta/bbands.rs | 149 + src/lib/qrust/ta/deriv.rs | 59 + src/lib/qrust/ta/ema.rs | 95 + src/lib/qrust/ta/macd.rs | 216 ++ src/lib/qrust/ta/mod.rs | 17 + src/lib/qrust/ta/obv.rs | 73 + src/lib/qrust/ta/pct.rs | 64 + src/lib/qrust/ta/rsi.rs | 135 + src/lib/qrust/ta/sma.rs | 88 + src/lib/qrust/types/mod.rs | 1 + src/lib/qrust/types/ta.rs | 315 +++ src/lib/qrust/utils/de.rs | 1 - 26 files changed, 4441 insertions(+), 104 deletions(-) create mode 100644 src/bin/trainer/mod.rs create mode 100644 src/lib/qrust/database/ta.rs create mode 100644 src/lib/qrust/ml/batcher.rs create mode 100644 src/lib/qrust/ml/dataset.rs create mode 100644 src/lib/qrust/ml/mod.rs create mode 100644 src/lib/qrust/ml/model.rs create mode 100644 src/lib/qrust/ta/bbands.rs create mode 100644 src/lib/qrust/ta/deriv.rs create mode 100644 src/lib/qrust/ta/ema.rs create mode 100644 src/lib/qrust/ta/macd.rs create mode 100644 src/lib/qrust/ta/mod.rs create mode 100644 src/lib/qrust/ta/obv.rs create mode 100644 src/lib/qrust/ta/pct.rs create mode 100644 src/lib/qrust/ta/rsi.rs create mode 100644 src/lib/qrust/ta/sma.rs create mode 100644 src/lib/qrust/types/ta.rs diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 06d27be..a24b6fc 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -22,7 +22,7 @@ build: cache: <<: *global_cache script: - - cargo +nightly build + - cargo +nightly build --workspace test: image: registry.karaolidis.com/karaolidis/qrust/rust @@ -30,7 +30,7 @@ test: cache: <<: *global_cache script: - - cargo +nightly test + - cargo +nightly test --workspace lint: image: registry.karaolidis.com/karaolidis/qrust/rust @@ -39,7 +39,7 @@ lint: <<: *global_cache script: - cargo +nightly fmt --all -- --check - - cargo +nightly clippy --all-targets --all-features + - cargo +nightly clippy --workspace --all-targets --all-features depcheck: image: registry.karaolidis.com/karaolidis/qrust/rust @@ -48,7 +48,7 @@ depcheck: <<: *global_cache script: - cargo +nightly outdated - - cargo +nightly udeps --all-targets + - cargo +nightly udeps --workspace --all-targets build-release: image: registry.karaolidis.com/karaolidis/qrust/rust diff --git a/Cargo.lock b/Cargo.lock index b2411bb..88da51a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,29 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "aho-corasick" version = "1.1.3" @@ -26,6 +49,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "allocator-api2" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" + [[package]] name = "android-tzdata" version = "0.1.1" @@ -49,32 +78,47 @@ checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" [[package]] name = "arc-swap" -version = "1.7.0" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b3d0060af21e8d11a926981cc00c6c1541aa91dd64b9f881985c3da1094425f" +checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "ash" +version = "0.37.3+1.3.251" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e9c3835d686b0a6084ab4234fcd1b07dbf6e4767dce60874b12356a25ecd4a" +dependencies = [ + "libloading 0.7.4", +] [[package]] name = "async-trait" -version = "0.1.78" +version = "0.1.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "461abc97219de0eaaf81fe3ef974a540158f3d079c2ab200f891f1a2ef201e85" +checksum = "a507401cad91ec6a857ed5513a2073c82a9b9048762b885bb98655b306964681" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] name = "autocfg" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" [[package]] name = "axum" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1236b4b292f6c4d6dc34604bb5120d85c3fe1d1aa596bd5cc52ca054d13e7b9e" +checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf" dependencies = [ "async-trait", "axum-core", @@ -96,7 +140,7 @@ dependencies = [ "serde_json", "serde_path_to_error", "serde_urlencoded", - "sync_wrapper", + "sync_wrapper 1.0.0", "tokio", "tower", "tower-layer", @@ -119,7 +163,7 @@ dependencies = [ "mime", "pin-project-lite", "rustversion", - "sync_wrapper", + "sync_wrapper 0.1.2", "tower-layer", "tower-service", "tracing", @@ -141,9 +185,9 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.69" +version = "0.3.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" dependencies = [ "addr2line", "cc", @@ -160,6 +204,53 @@ version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "bincode" +version = "2.0.0-rc.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f11ea1a0346b94ef188834a65c068a03aec181c94896d481d7a0a40d85b0ce95" +dependencies = [ + "serde", +] + +[[package]] +name = "bindgen_cuda" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "853f25ad4724e82569cc7dd3b08048d21bd15950208f8b0ceeab6ac062b33c1f" +dependencies = [ + "glob", + "num_cpus", + "rayon", +] + +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + +[[package]] +name = "bit_field" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" + [[package]] name = "bitflags" version = "1.3.2" @@ -172,6 +263,12 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +[[package]] +name = "block" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" + [[package]] name = "block-buffer" version = "0.10.4" @@ -196,6 +293,269 @@ version = "3.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" +[[package]] +name = "burn" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6b703e5dae87b2146649b64af54688ff86e16cf69fd19d28c43c8f9656d7d7c" +dependencies = [ + "burn-core", + "burn-train", +] + +[[package]] +name = "burn-autodiff" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f306e1b2e480fa0960c3130a68ca5e0fa54b3e33ed2fda7cf2121434703dd771" +dependencies = [ + "burn-common", + "burn-tensor", + "derive-new", + "spin", +] + +[[package]] +name = "burn-candle" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc87b644a2d83cc1b7c05d1176e9e24fb6394272256ab9ab8324ff7c4fe0e6a0" +dependencies = [ + "burn-tensor", + "candle-core", + "derive-new", + "half", +] + +[[package]] +name = "burn-common" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1267068969f094323b62693df0c3b45d3b08a0568f3c3467e6a5c3207e6807c8" +dependencies = [ + "async-trait", + "derive-new", + "getrandom", + "rand", + "serde", + "spin", + "uuid", + "web-time", +] + +[[package]] +name = "burn-compute" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1b51588cf7c84976f6241a9ac5f77857712b8bf443dab77296c260785033fe8" +dependencies = [ + "burn-common", + "derive-new", + "dirs", + "hashbrown 0.14.3", + "log", + "md5", + "serde", + "serde_json", + "spin", + "web-time", +] + +[[package]] +name = "burn-core" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b11d8fd1e8c656eee1a0bb503b798c4583904dcaf7a369cbb8fdfd3acc3d0ab" +dependencies = [ + "bincode", + "burn-autodiff", + "burn-candle", + "burn-common", + "burn-dataset", + "burn-derive", + "burn-fusion", + "burn-ndarray", + "burn-tch", + "burn-tensor", + "burn-wgpu", + "derive-new", + "flate2", + "half", + "hashbrown 0.14.3", + "libm", + "log", + "rand", + "rmp-serde", + "serde", + "serde_json", + "spin", +] + +[[package]] +name = "burn-dataset" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6050891281ae38ee9dc24d1d5badd084247717b15e3dcdae562a81456a41c6e" +dependencies = [ + "csv", + "derive-new", + "dirs", + "gix-tempfile", + "image", + "r2d2", + "r2d2_sqlite", + "rand", + "rmp-serde", + "rusqlite", + "sanitize-filename", + "serde", + "serde_json", + "serde_rusqlite", + "strum", + "strum_macros", + "tempfile", + "thiserror", +] + +[[package]] +name = "burn-derive" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70f149de5f32baa3f2191c374edab71e5a323bade05eb6092c702aed76cdcb7b" +dependencies = [ + "derive-new", + "proc-macro2", + "quote", + "syn 2.0.55", +] + +[[package]] +name = "burn-fusion" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f512f780beaefca46088c4e4a80595511fbc3b35545118281fbf49f1fca767b4" +dependencies = [ + "burn-common", + "burn-tensor", + "derive-new", + "hashbrown 0.14.3", + "log", + "serde", + "spin", +] + +[[package]] +name = "burn-ndarray" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aef9fb0b72a1c0a112ed51e35284fb663d3ba3fd98f3a3bfa32db39fd24ae4d" +dependencies = [ + "burn-autodiff", + "burn-common", + "burn-tensor", + "derive-new", + "libm", + "matrixmultiply", + "ndarray", + "num-traits", + "rand", + "rayon", + "spin", +] + +[[package]] +name = "burn-tch" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d7aec36d836c5a11714480089738120899e2c91f6fe2e23abd09ec4a68a803" +dependencies = [ + "burn-tensor", + "half", + "libc", + "rand", + "tch", +] + +[[package]] +name = "burn-tensor" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad09aeb0f2428a4ee91f9876a7d71cef6feb1fcacdab6389362dd878ec5f9b27" +dependencies = [ + "burn-common", + "derive-new", + "half", + "hashbrown 0.14.3", + "libm", + "num-traits", + "rand", + "rand_distr", + "serde", +] + +[[package]] +name = "burn-train" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd5536e98b23dd5047728f288e61e8a4d9fbffef6f55086d3483c2464758508d" +dependencies = [ + "burn-core", + "crossterm", + "derive-new", + "log", + "nvml-wrapper", + "ratatui", + "serde", + "sysinfo", + "systemstat", + "tracing-appender", + "tracing-core", + "tracing-subscriber", +] + +[[package]] +name = "burn-wgpu" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "231d2deb14a02838c29dd5e90d1a87a9578d76bda7b02d5c7a77e5440ef6ae95" +dependencies = [ + "burn-common", + "burn-compute", + "burn-tensor", + "bytemuck", + "derive-new", + "futures-intrusive", + "hashbrown 0.14.3", + "log", + "num-traits", + "pollster", + "rand", + "serde", + "spin", + "text_placeholder", + "wgpu", +] + +[[package]] +name = "bytemuck" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d6d68c57235a3a081186990eca2867354726650f42f7516ca50c28d6281fd15" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4da9a32f3fed317401fa3c862968128267c3106685286e15d5aaa3d7389c2f60" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.55", +] + [[package]] name = "byteorder" version = "1.5.0" @@ -204,15 +564,84 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" + +[[package]] +name = "bytesize" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e368af43e418a04d52505cf3dbc23dda4e3407ae2fa99fd0e4f308ce546acc" + +[[package]] +name = "bzip2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" +dependencies = [ + "bzip2-sys", + "libc", +] + +[[package]] +name = "bzip2-sys" +version = "0.1.11+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + +[[package]] +name = "candle-core" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db8659ea87ee8197d2fc627348916cce0561330ee7ae3874e771691d3cecb2f" +dependencies = [ + "byteorder", + "candle-kernels", + "cudarc", + "gemm", + "half", + "memmap2", + "num-traits", + "num_cpus", + "rand", + "rand_distr", + "rayon", + "safetensors 0.4.2", + "thiserror", + "yoke", + "zip", +] + +[[package]] +name = "candle-kernels" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d80cdd5f1cc60d30ba61353cdba5accd0fbc4d4ef2fe707fcb5179a9821adbea" +dependencies = [ + "bindgen_cuda", +] + +[[package]] +name = "cassowary" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" [[package]] name = "cc" version = "1.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" +dependencies = [ + "jobserver", + "libc", +] [[package]] name = "cfg-if" @@ -222,9 +651,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.35" +version = "0.4.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaf5903dcbc0a39312feb77df2ff4c76387d591b9fc7b04a238dcf8bb62639a" +checksum = "8a0d04d43504c61aa6c7531f1871dd0d418d91130162063b789da00fd7057a5e" dependencies = [ "android-tzdata", "iana-time-zone", @@ -234,12 +663,13 @@ dependencies = [ ] [[package]] -name = "claims" -version = "0.7.1" +name = "cipher" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6995bbe186456c36307f8ea36be3eefe42f49d106896414e18efc4fb2f846b5" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ - "autocfg", + "crypto-common", + "inout", ] [[package]] @@ -289,6 +719,34 @@ dependencies = [ "cc", ] +[[package]] +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width", +] + +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + +[[package]] +name = "com-rs" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf43edc576402991846b093a7ca18a3477e0ef9c588cde84964b5d3e43016642" + +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + [[package]] name = "core-foundation" version = "0.9.4" @@ -305,6 +763,17 @@ version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +[[package]] +name = "core-graphics-types" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "libc", +] + [[package]] name = "cpufeatures" version = "0.2.12" @@ -314,12 +783,80 @@ dependencies = [ "libc", ] +[[package]] +name = "crc32fast" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" +[[package]] +name = "crossterm" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df" +dependencies = [ + "bitflags 2.5.0", + "crossterm_winapi", + "libc", + "mio", + "parking_lot", + "signal-hook", + "signal-hook-mio", + "winapi", +] + +[[package]] +name = "crossterm_winapi" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" +dependencies = [ + "winapi", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + [[package]] name = "crypto-common" version = "0.1.6" @@ -330,6 +867,47 @@ dependencies = [ "typenum", ] +[[package]] +name = "csv" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac574ff4d437a7b5ad237ef331c17ccca63c46479e5b5453eb8e10bb99a759fe" +dependencies = [ + "csv-core", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5efa2b3d7902f4b634a20cae3c9c4e6209dc4779feb6863329607560143efa70" +dependencies = [ + "memchr", +] + +[[package]] +name = "cudarc" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9395df0cab995685664e79cc35ad6302bf08fb9c5d82301875a183affe1278b1" +dependencies = [ + "half", +] + +[[package]] +name = "d3d12" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e16e44ab292b1dddfdaf7be62cfd8877df52f2f3fde5858d95bab606be259f20" +dependencies = [ + "bitflags 2.5.0", + "libloading 0.8.3", + "winapi", +] + [[package]] name = "darling" version = "0.20.8" @@ -351,7 +929,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] @@ -362,7 +940,7 @@ checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f" dependencies = [ "darling_core", "quote", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] @@ -405,6 +983,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "derive-new" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d150dea618e920167e5973d70ae6ece4385b7164e0d799fe7c122dd0a5d912ad" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.55", +] + [[package]] name = "destructure_traitobject" version = "0.2.0" @@ -419,6 +1008,28 @@ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", "crypto-common", + "subtle", +] + +[[package]] +name = "dirs" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.48.0", ] [[package]] @@ -427,6 +1038,16 @@ version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" +[[package]] +name = "dyn-stack" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e53799688f5632f364f8fb387488dd05db9fe45db7011be066fc20e7027f8b" +dependencies = [ + "bytemuck", + "reborrow", +] + [[package]] name = "either" version = "1.10.0" @@ -442,6 +1063,18 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "enum-as-inner" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ffccbb6966c05b32ef8fbac435df276c4ae4d3dc55a8cd0eb9745e6c12f546a" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "syn 2.0.55", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -459,10 +1092,78 @@ dependencies = [ ] [[package]] -name = "fastrand" -version = "2.0.1" +name = "exr" +version = "1.72.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" +checksum = "887d93f60543e9a9362ef8a21beedd0a833c5d9610e18c67abe15a5963dcb1a4" +dependencies = [ + "bit_field", + "flume", + "half", + "lebe", + "miniz_oxide", + "rayon-core", + "smallvec", + "zune-inflate", +] + +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + +[[package]] +name = "fallible-streaming-iterator" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" + +[[package]] +name = "faster-hex" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2a2b11eda1d40935b26cf18f6833c526845ae8c41e58d09af6adeb6f0269183" +dependencies = [ + "serde", +] + +[[package]] +name = "fastrand" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" + +[[package]] +name = "fdeflate" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f9bfee30e4dedf0ab8b422f03af778d9612b63f502710fc500a334ebe2de645" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "flate2" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "flume" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" +dependencies = [ + "futures-core", + "futures-sink", + "nanorand", + "spin", +] [[package]] name = "fnv" @@ -476,7 +1177,28 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" dependencies = [ - "foreign-types-shared", + "foreign-types-shared 0.1.1", +] + +[[package]] +name = "foreign-types" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" +dependencies = [ + "foreign-types-macros", + "foreign-types-shared 0.3.1", +] + +[[package]] +name = "foreign-types-macros" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.55", ] [[package]] @@ -485,6 +1207,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" +[[package]] +name = "foreign-types-shared" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" + [[package]] name = "form_urlencoded" version = "1.2.1" @@ -536,6 +1264,17 @@ dependencies = [ "futures-util", ] +[[package]] +name = "futures-intrusive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" +dependencies = [ + "futures-core", + "lock_api", + "parking_lot", +] + [[package]] name = "futures-io" version = "0.3.30" @@ -550,7 +1289,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] @@ -589,6 +1328,124 @@ dependencies = [ "slab", ] +[[package]] +name = "gemm" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ab24cc62135b40090e31a76a9b2766a501979f3070fa27f689c27ec04377d32" +dependencies = [ + "dyn-stack", + "gemm-c32", + "gemm-c64", + "gemm-common", + "gemm-f16", + "gemm-f32", + "gemm-f64", + "num-complex", + "num-traits", + "paste", + "raw-cpuid 10.7.0", + "seq-macro", +] + +[[package]] +name = "gemm-c32" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9c030d0b983d1e34a546b86e08f600c11696fde16199f971cd46c12e67512c0" +dependencies = [ + "dyn-stack", + "gemm-common", + "num-complex", + "num-traits", + "paste", + "raw-cpuid 10.7.0", + "seq-macro", +] + +[[package]] +name = "gemm-c64" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbb5f2e79fefb9693d18e1066a557b4546cd334b226beadc68b11a8f9431852a" +dependencies = [ + "dyn-stack", + "gemm-common", + "num-complex", + "num-traits", + "paste", + "raw-cpuid 10.7.0", + "seq-macro", +] + +[[package]] +name = "gemm-common" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2e7ea062c987abcd8db95db917b4ffb4ecdfd0668471d8dc54734fdff2354e8" +dependencies = [ + "bytemuck", + "dyn-stack", + "half", + "num-complex", + "num-traits", + "once_cell", + "paste", + "pulp", + "raw-cpuid 10.7.0", + "rayon", + "seq-macro", + "sysctl", +] + +[[package]] +name = "gemm-f16" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ca4c06b9b11952071d317604acb332e924e817bd891bec8dfb494168c7cedd4" +dependencies = [ + "dyn-stack", + "gemm-common", + "gemm-f32", + "half", + "num-complex", + "num-traits", + "paste", + "raw-cpuid 10.7.0", + "rayon", + "seq-macro", +] + +[[package]] +name = "gemm-f32" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9a69f51aaefbd9cf12d18faf273d3e982d9d711f60775645ed5c8047b4ae113" +dependencies = [ + "dyn-stack", + "gemm-common", + "num-complex", + "num-traits", + "paste", + "raw-cpuid 10.7.0", + "seq-macro", +] + +[[package]] +name = "gemm-f64" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa397a48544fadf0b81ec8741e5c0fba0043008113f71f2034def1935645d2b0" +dependencies = [ + "dyn-stack", + "gemm-common", + "num-complex", + "num-traits", + "paste", + "raw-cpuid 10.7.0", + "seq-macro", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -606,8 +1463,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi", + "wasm-bindgen", +] + +[[package]] +name = "gif" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb2d69b19215e18bb912fa30f7ce15846e301408695e44e0ef719f1da9e19f2" +dependencies = [ + "color_quant", + "weezl", ] [[package]] @@ -616,6 +1485,96 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +[[package]] +name = "gix-features" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d46a4a5c6bb5bebec9c0d18b65ada20e6517dbd7cf855b87dd4bbdce3a771b2" +dependencies = [ + "gix-hash", + "gix-trace", + "libc", +] + +[[package]] +name = "gix-fs" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20e86eb040f5776a5ade092282e51cdcad398adb77d948b88d17583c2ae4e107" +dependencies = [ + "gix-features", +] + +[[package]] +name = "gix-hash" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f8cf8c2266f63e582b7eb206799b63aa5fa68ee510ad349f637dfe2d0653de0" +dependencies = [ + "faster-hex", + "thiserror", +] + +[[package]] +name = "gix-tempfile" +version = "11.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388dd29114a86ec69b28d1e26d6d63a662300ecf61ab3f4cc578f7d7dc9e7e23" +dependencies = [ + "dashmap", + "gix-fs", + "libc", + "once_cell", + "parking_lot", + "signal-hook", + "signal-hook-registry", + "tempfile", +] + +[[package]] +name = "gix-trace" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b838b2db8f62c9447d483a4c28d251b67fee32741a82cb4d35e9eb4e9fdc5ab" + +[[package]] +name = "gl_generator" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a95dfc23a2b4a9a2f5ab41d194f8bfda3cabec42af4e39f08c339eb2a0c124d" +dependencies = [ + "khronos_api", + "log", + "xml-rs", +] + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "glow" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd348e04c43b32574f2de31c8bb397d96c9fcfa1371bd4ca6d8bdc464ab121b1" +dependencies = [ + "js-sys", + "slotmap", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "glutin_wgl_sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8098adac955faa2d31079b65dc48841251f69efd3ac25477903fc424362ead" +dependencies = [ + "gl_generator", +] + [[package]] name = "governor" version = "0.6.3" @@ -636,6 +1595,59 @@ dependencies = [ "spinning_top", ] +[[package]] +name = "gpu-alloc" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbcd2dba93594b227a1f57ee09b8b9da8892c34d55aa332e034a228d0fe6a171" +dependencies = [ + "bitflags 2.5.0", + "gpu-alloc-types", +] + +[[package]] +name = "gpu-alloc-types" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98ff03b468aa837d70984d55f5d3f846f6ec31fe34bbb97c4f85219caeee1ca4" +dependencies = [ + "bitflags 2.5.0", +] + +[[package]] +name = "gpu-allocator" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40fe17c8a05d60c38c0a4e5a3c802f2f1ceb66b76c67d96ffb34bef0475a7fad" +dependencies = [ + "backtrace", + "log", + "presser", + "thiserror", + "winapi", + "windows", +] + +[[package]] +name = "gpu-descriptor" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc11df1ace8e7e564511f53af41f3e42ddc95b56fd07b3f4445d2a6048bc682c" +dependencies = [ + "bitflags 2.5.0", + "gpu-descriptor-types", + "hashbrown 0.14.3", +] + +[[package]] +name = "gpu-descriptor-types" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bf0b36e6f090b7e1d8a4b49c0cb81c1f8376f72198c65dd3ad9ff3556b8b78c" +dependencies = [ + "bitflags 2.5.0", +] + [[package]] name = "h2" version = "0.4.3" @@ -648,24 +1660,77 @@ dependencies = [ "futures-sink", "futures-util", "http 1.1.0", - "indexmap 2.2.5", + "indexmap 2.2.6", "slab", "tokio", "tokio-util", "tracing", ] +[[package]] +name = "half" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5eceaaeec696539ddaf7b333340f1af35a5aa87ae3e4f3ead0532f72affab2e" +dependencies = [ + "bytemuck", + "cfg-if", + "crunchy", + "num-traits", + "rand", + "rand_distr", + "serde", +] + [[package]] name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash", +] + [[package]] name = "hashbrown" version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +dependencies = [ + "ahash", + "allocator-api2", + "serde", +] + +[[package]] +name = "hashlink" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" +dependencies = [ + "hashbrown 0.14.3", +] + +[[package]] +name = "hassle-rs" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1397650ee315e8891a0df210707f0fc61771b0cc518c3023896064c5407cb3b0" +dependencies = [ + "bitflags 1.3.2", + "com-rs", + "libc", + "libloading 0.7.4", + "thiserror", + "widestring", + "winapi", +] [[package]] name = "heck" @@ -676,6 +1741,12 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "hermit-abi" version = "0.3.9" @@ -688,6 +1759,21 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hexf-parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + [[package]] name = "http" version = "0.2.12" @@ -866,7 +1952,7 @@ dependencies = [ "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "windows-core", + "windows-core 0.52.0", ] [[package]] @@ -894,6 +1980,24 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "image" +version = "0.24.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5690139d2f55868e080017335e4b94cb7414274c74f1669c84fb5feba2c9f69d" +dependencies = [ + "bytemuck", + "byteorder", + "color_quant", + "exr", + "gif", + "jpeg-decoder", + "num-traits", + "png", + "qoi", + "tiff", +] + [[package]] name = "indexmap" version = "1.9.3" @@ -907,15 +2011,30 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.5" +version = "2.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", "hashbrown 0.14.3", "serde", ] +[[package]] +name = "indoc" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5" + +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + [[package]] name = "instant" version = "0.1.12" @@ -942,9 +2061,27 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "jobserver" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6" +dependencies = [ + "libc", +] + +[[package]] +name = "jpeg-decoder" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0" +dependencies = [ + "rayon", +] [[package]] name = "js-sys" @@ -955,18 +2092,89 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "khronos-egl" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6aae1df220ece3c0ada96b8153459b67eebe9ae9212258bb0134ae60416fdf76" +dependencies = [ + "libc", + "libloading 0.8.3", + "pkg-config", +] + +[[package]] +name = "khronos_api" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" + [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +[[package]] +name = "lebe" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" + [[package]] name = "libc" version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "libloading" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" +dependencies = [ + "cfg-if", + "windows-targets 0.52.4", +] + +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "libredox" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +dependencies = [ + "bitflags 2.5.0", + "libc", + "redox_syscall", +] + +[[package]] +name = "libsqlite3-sys" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4e226dcd58b4be396f7bd3c20da8fdee2911400705297ba7d2d7cc2c30f716" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + [[package]] name = "linux-raw-sys" version = "0.4.13" @@ -1026,6 +2234,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "lru" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3262e75e648fce39813cb56ac41f3c3e3f65217ebf3844d818d1f9398cfb0dc" +dependencies = [ + "hashbrown 0.14.3", +] + [[package]] name = "lz4" version = "1.24.0" @@ -1046,6 +2263,15 @@ dependencies = [ "libc", ] +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + [[package]] name = "matchit" version = "0.7.3" @@ -1053,10 +2279,54 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" [[package]] -name = "memchr" -version = "2.7.1" +name = "matrixmultiply" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +checksum = "7574c1cf36da4798ab73da5b215bbf444f50718207754cb522201d78d1cd0ff2" +dependencies = [ + "autocfg", + "num_cpus", + "once_cell", + "rawpointer", + "thread-tree", +] + +[[package]] +name = "md5" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" + +[[package]] +name = "memchr" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" + +[[package]] +name = "memmap2" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322" +dependencies = [ + "libc", + "stable_deref_trait", +] + +[[package]] +name = "metal" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c43f73953f8cbe511f021b58f18c3ce1c3d1ae13fe953293e13345bf83217f25" +dependencies = [ + "bitflags 2.5.0", + "block", + "core-graphics-types", + "foreign-types 0.5.0", + "log", + "objc", + "paste", +] [[package]] name = "mime" @@ -1064,6 +2334,12 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" version = "0.7.2" @@ -1071,6 +2347,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" dependencies = [ "adler", + "simd-adler32", ] [[package]] @@ -1080,10 +2357,40 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", + "log", "wasi", "windows-sys 0.48.0", ] +[[package]] +name = "naga" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae585df4b6514cf8842ac0f1ab4992edc975892704835b549cf818dc0191249e" +dependencies = [ + "bit-set", + "bitflags 2.5.0", + "codespan-reporting", + "hexf-parse", + "indexmap 2.2.6", + "log", + "num-traits", + "rustc-hash", + "spirv", + "termcolor", + "thiserror", + "unicode-xid", +] + +[[package]] +name = "nanorand" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" +dependencies = [ + "getrandom", +] + [[package]] name = "native-tls" version = "0.2.11" @@ -1102,12 +2409,36 @@ dependencies = [ "tempfile", ] +[[package]] +name = "ndarray" +version = "0.15.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb12d4e967ec485a5f71c6311fe28158e9d6f4bc4a447b474184d0f91a8fa32" +dependencies = [ + "matrixmultiply", + "num-complex", + "num-integer", + "num-traits", + "rawpointer", + "rayon", +] + [[package]] name = "no-std-compat" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c" +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "nonempty" version = "0.10.0" @@ -1123,12 +2454,50 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38bf9645c8b145698bb0b18a4637dcacbc421ea49bef2317e4fd8065a387cf21" +[[package]] +name = "ntapi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4" +dependencies = [ + "winapi", +] + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + +[[package]] +name = "num-complex" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23c6602fda94a57c990fe0df199a035d83576b496aa29f4e634a8ac6004e68a6" +dependencies = [ + "bytemuck", + "num-traits", +] + [[package]] name = "num-conv" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.18" @@ -1136,6 +2505,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -1157,6 +2527,48 @@ dependencies = [ "libc", ] +[[package]] +name = "nvml-wrapper" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd21b9f5a1cce3c3515c9ffa85f5c7443e07162dae0ccf4339bb7ca38ad3454" +dependencies = [ + "bitflags 1.3.2", + "libloading 0.7.4", + "nvml-wrapper-sys", + "static_assertions", + "thiserror", + "wrapcenum-derive", +] + +[[package]] +name = "nvml-wrapper-sys" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c961a2ea9e91c59a69b78e69090f6f5b867bb46c0c56de9482da232437c4987e" +dependencies = [ + "libloading 0.7.4", +] + +[[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", + "objc_exception", +] + +[[package]] +name = "objc_exception" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4" +dependencies = [ + "cc", +] + [[package]] name = "object" version = "0.32.2" @@ -1180,7 +2592,7 @@ checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" dependencies = [ "bitflags 2.5.0", "cfg-if", - "foreign-types", + "foreign-types 0.3.2", "libc", "once_cell", "openssl-macros", @@ -1195,7 +2607,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] @@ -1206,9 +2618,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.101" +version = "0.9.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dda2b0f344e78efc2facf7d195d098df0dd72151b26ab98da807afc26c198dff" +checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2" dependencies = [ "cc", "libc", @@ -1216,6 +2628,12 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + [[package]] name = "ordered-float" version = "2.10.1" @@ -1225,6 +2643,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + [[package]] name = "parking_lot" version = "0.12.1" @@ -1248,6 +2672,35 @@ dependencies = [ "windows-targets 0.48.5", ] +[[package]] +name = "password-hash" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" +dependencies = [ + "base64ct", + "rand_core", + "subtle", +] + +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest", + "hmac", + "password-hash", + "sha2", +] + [[package]] name = "percent-encoding" version = "2.3.1" @@ -1271,7 +2724,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] @@ -1292,6 +2745,25 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +[[package]] +name = "png" +version = "0.17.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06e4b0d3d1312775e782c86c91a111aa1f910cbb65e1337f9975b5f9a554b5e1" +dependencies = [ + "bitflags 1.3.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "pollster" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22686f4785f02a4fcc856d3b3bb19bf6c8160d103f7a99cc258bddd0251dc7f2" + [[package]] name = "portable-atomic" version = "1.6.0" @@ -1310,6 +2782,12 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "presser" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8cf8e6a8aa66ce33f63993ffc4ea4271eb5b0530a9002db8455ea6050c77bfa" + [[package]] name = "proc-macro2" version = "1.0.79" @@ -1319,6 +2797,33 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "profiling" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d84d1d7a6ac92673717f9f6d1518374ef257669c24ebc5ac25d5033828be58" + +[[package]] +name = "pulp" +version = "0.18.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03457ac216146f43f921500bac4e892d5cd32b0479b929cbfc90f95cd6c599c2" +dependencies = [ + "bytemuck", + "libm", + "num-complex", + "reborrow", +] + +[[package]] +name = "qoi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001" +dependencies = [ + "bytemuck", +] + [[package]] name = "qrust" version = "0.1.0" @@ -1326,7 +2831,7 @@ dependencies = [ "async-trait", "axum", "backoff", - "claims", + "burn", "clickhouse", "dotenv", "futures-util", @@ -1337,6 +2842,8 @@ dependencies = [ "log", "log4rs", "nonempty", + "rand", + "rayon", "regex", "reqwest", "serde", @@ -1360,7 +2867,7 @@ dependencies = [ "crossbeam-utils", "libc", "once_cell", - "raw-cpuid", + "raw-cpuid 11.0.1", "wasi", "web-sys", "winapi", @@ -1375,6 +2882,28 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r2d2" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51de85fb3fb6524929c8a2eb85e6b6d363de4e8c48f9e2c2eac4944abc181c93" +dependencies = [ + "log", + "parking_lot", + "scheduled-thread-pool", +] + +[[package]] +name = "r2d2_sqlite" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dc290b669d30e20751e813517bbe13662d020419c5c8818ff10b6e8bb7777f6" +dependencies = [ + "r2d2", + "rusqlite", + "uuid", +] + [[package]] name = "rand" version = "0.8.5" @@ -1405,6 +2934,51 @@ dependencies = [ "getrandom", ] +[[package]] +name = "rand_distr" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31" +dependencies = [ + "num-traits", + "rand", +] + +[[package]] +name = "range-alloc" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8a99fddc9f0ba0a85884b8d14e3592853e787d581ca1816c91349b10e4eeab" + +[[package]] +name = "ratatui" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5659e52e4ba6e07b2dad9f1158f578ef84a73762625ddb51536019f34d180eb" +dependencies = [ + "bitflags 2.5.0", + "cassowary", + "crossterm", + "indoc", + "itertools", + "lru", + "paste", + "stability", + "strum", + "time", + "unicode-segmentation", + "unicode-width", +] + +[[package]] +name = "raw-cpuid" +version = "10.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c297679cb867470fa8c9f67dbba74a78d78e3e98d7cf2b08d6d71540f797332" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "raw-cpuid" version = "11.0.1" @@ -1414,6 +2988,44 @@ dependencies = [ "bitflags 2.5.0", ] +[[package]] +name = "raw-window-handle" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" + +[[package]] +name = "rawpointer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "reborrow" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03251193000f4bd3b042892be858ee50e8b3719f2b08e5833ac4353724632430" + [[package]] name = "redox_syscall" version = "0.4.1" @@ -1424,10 +3036,21 @@ dependencies = [ ] [[package]] -name = "regex" -version = "1.10.3" +name = "redox_users" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" +dependencies = [ + "getrandom", + "libredox", + "thiserror", +] + +[[package]] +name = "regex" +version = "1.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" dependencies = [ "aho-corasick", "memchr", @@ -1448,15 +3071,21 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" + +[[package]] +name = "renderdoc-sys" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832" [[package]] name = "reqwest" -version = "0.12.0" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58b48d98d932f4ee75e541614d32a7f44c889b72bd9c2e04d95edd135989df88" +checksum = "2d66674f2b6fb864665eea7a3c1ac4e3dfacd2fda83cf6f935a612e01b0e3338" dependencies = [ "base64", "bytes", @@ -1482,7 +3111,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", - "sync_wrapper", + "sync_wrapper 0.1.2", "system-configuration", "tokio", "tokio-native-tls", @@ -1494,12 +3123,69 @@ dependencies = [ "winreg", ] +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if", + "getrandom", + "libc", + "spin", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rmp" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f9860a6cc38ed1da53456442089b4dfa35e7cedaa326df63017af88385e6b20" +dependencies = [ + "byteorder", + "num-traits", + "paste", +] + +[[package]] +name = "rmp-serde" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bffea85eea980d8a74453e5d02a8d93028f3c34725de143085a844ebe953258a" +dependencies = [ + "byteorder", + "rmp", + "serde", +] + +[[package]] +name = "rusqlite" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a78046161564f5e7cd9008aff3b2990b3850dc8e0349119b98e8f251e099f24d" +dependencies = [ + "bitflags 2.5.0", + "fallible-iterator", + "fallible-streaming-iterator", + "hashlink", + "libsqlite3-sys", + "smallvec", +] + [[package]] name = "rustc-demangle" version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rustix" version = "0.38.32" @@ -1513,6 +3199,20 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rustls" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99008d7ad0bbbea527ec27bddbc0e432c5b87d8175178cee68d2eec9c4a1813c" +dependencies = [ + "log", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + [[package]] name = "rustls-pemfile" version = "1.0.4" @@ -1522,6 +3222,23 @@ dependencies = [ "base64", ] +[[package]] +name = "rustls-pki-types" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecd36cc4259e3e4514335c4a138c6b43171a8d61d8f5c9348f9fc7529416f247" + +[[package]] +name = "rustls-webpki" +version = "0.102.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faaa0a62740bedb9b2ef5afa303da42764c012f743917351dc9a237ea1663610" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + [[package]] name = "rustversion" version = "1.0.14" @@ -1534,6 +3251,45 @@ version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" +[[package]] +name = "safetensors" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d93279b86b3de76f820a8854dd06cbc33cfa57a417b19c47f6a25280112fb1df" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "safetensors" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d980e6bfb34436fb0a81e42bc41af43f11805bbbca443e7f68e9faaabe669ed" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "sanitize-filename" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ed72fbaf78e6f2d41744923916966c4fbe3d7c74e3037a8ee482f1115572603" +dependencies = [ + "lazy_static", + "regex", +] + [[package]] name = "schannel" version = "0.1.23" @@ -1543,6 +3299,15 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "scheduled-thread-pool" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cbc66816425a074528352f5789333ecff06ca41b36b0b0efdfbb29edc391a19" +dependencies = [ + "parking_lot", +] + [[package]] name = "scopeguard" version = "1.2.0" @@ -1555,7 +3320,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b5e421024b5e5edfbaa8e60ecf90bda9dbffc602dbb230e6028763f85f0c68c" dependencies = [ - "heck", + "heck 0.3.3", "proc-macro2", "quote", "syn 1.0.109", @@ -1584,6 +3349,12 @@ dependencies = [ "libc", ] +[[package]] +name = "seq-macro" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3f0bf26fd526d2a95683cd0f87bf103b8539e2ca1ef48ce002d67aad59aa0b4" + [[package]] name = "serde" version = "1.0.197" @@ -1622,7 +3393,7 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] @@ -1638,9 +3409,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.114" +version = "1.0.115" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" +checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" dependencies = [ "itoa", "ryu", @@ -1665,7 +3436,17 @@ checksum = "0b2e6b945e9d3df726b65d6ee24060aff8e3533d431f677a9695db04eff9dfdb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", +] + +[[package]] +name = "serde_rusqlite" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4600dac14aada464c5584d327baa164e372153309bc4c0fb1498bbfbaa5a028b" +dependencies = [ + "rusqlite", + "serde", ] [[package]] @@ -1699,7 +3480,7 @@ dependencies = [ "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.2.5", + "indexmap 2.2.6", "serde", "serde_derive", "serde_json", @@ -1716,16 +3497,16 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] name = "serde_yaml" -version = "0.9.33" +version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0623d197252096520c6f2a5e1171ee436e5af99a5d7caa2891e55e61950e6d9" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.2.5", + "indexmap 2.2.6", "itoa", "ryu", "serde", @@ -1754,6 +3535,62 @@ dependencies = [ "digest", ] +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "signal-hook" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-mio" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af" +dependencies = [ + "libc", + "mio", + "signal-hook", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +dependencies = [ + "libc", +] + +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + [[package]] name = "slab" version = "0.4.9" @@ -1764,10 +3601,19 @@ dependencies = [ ] [[package]] -name = "smallvec" -version = "1.13.1" +name = "slotmap" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" +checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a" +dependencies = [ + "version_check", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "socket2" @@ -1779,6 +3625,15 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + [[package]] name = "spinning_top" version = "0.3.0" @@ -1788,6 +3643,32 @@ dependencies = [ "lock_api", ] +[[package]] +name = "spirv" +version = "0.2.0+1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "246bfa38fe3db3f1dfc8ca5a2cdeb7348c78be2112740cc0ec8ef18b6d94f830" +dependencies = [ + "bitflags 1.3.2", + "num-traits", +] + +[[package]] +name = "stability" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebd1b177894da2a2d9120208c3386066af06a488255caabc5de8ddca22dbc3ce" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "static_assertions" version = "1.1.0" @@ -1800,6 +3681,34 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "strum" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.55", +] + +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + [[package]] name = "syn" version = "1.0.109" @@ -1813,9 +3722,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.53" +version = "2.0.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032" +checksum = "002a1b3dbf967edfafc32655d0f377ab0bb7b994aa1d32c8cc7e9b8bf3ebb8f0" dependencies = [ "proc-macro2", "quote", @@ -1828,6 +3737,52 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" +[[package]] +name = "sync_wrapper" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384595c11a4e2969895cad5a8c4029115f5ab956a9e5ef4de79d11a426e5f20c" + +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.55", +] + +[[package]] +name = "sysctl" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec7dddc5f0fee506baf8b9fdb989e242f17e4b11c61dfbb0635b705217199eea" +dependencies = [ + "bitflags 2.5.0", + "byteorder", + "enum-as-inner", + "libc", + "thiserror", + "walkdir", +] + +[[package]] +name = "sysinfo" +version = "0.29.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd727fc423c2060f6c92d9534cef765c65a6ed3f428a03d7def74a8c4348e666" +dependencies = [ + "cfg-if", + "core-foundation-sys", + "libc", + "ntapi", + "once_cell", + "rayon", + "winapi", +] + [[package]] name = "system-configuration" version = "0.5.1" @@ -1849,6 +3804,37 @@ dependencies = [ "libc", ] +[[package]] +name = "systemstat" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a24aec24a9312c83999a28e3ef9db7e2afd5c64bf47725b758cdc1cafd5b0bd2" +dependencies = [ + "bytesize", + "lazy_static", + "libc", + "nom", + "time", + "winapi", +] + +[[package]] +name = "tch" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c7cb00bc2770454b515388d45be7097a3ded2eca172f3dcdb7ca4cc06c40bf1" +dependencies = [ + "half", + "lazy_static", + "libc", + "ndarray", + "rand", + "safetensors 0.3.3", + "thiserror", + "torch-sys", + "zip", +] + [[package]] name = "tempfile" version = "3.10.1" @@ -1861,6 +3847,26 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "text_placeholder" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512104f982ce6f50def5340f9d7d14cc21f7a859e9ccd251aa19d12e1345c070" +dependencies = [ + "hashbrown 0.13.2", + "serde", + "serde_json", +] + [[package]] name = "thiserror" version = "1.0.58" @@ -1878,7 +3884,7 @@ checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] @@ -1891,6 +3897,36 @@ dependencies = [ "winapi", ] +[[package]] +name = "thread-tree" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbd370cb847953a25954d9f63e14824a36113f8c72eecf6eccef5dc4b45d630" +dependencies = [ + "crossbeam-channel", +] + +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "tiff" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e" +dependencies = [ + "flate2", + "jpeg-decoder", + "weezl", +] + [[package]] name = "time" version = "0.3.34" @@ -1941,9 +3977,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.36.0" +version = "1.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931" +checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" dependencies = [ "backtrace", "bytes", @@ -1964,7 +4000,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] @@ -2005,6 +4041,21 @@ dependencies = [ "tracing", ] +[[package]] +name = "torch-sys" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29e0244e5b148a31dd7fe961165037d1927754d024095c1013937532d7e73a22" +dependencies = [ + "anyhow", + "cc", + "libc", + "serde", + "serde_json", + "ureq", + "zip", +] + [[package]] name = "tower" version = "0.4.13" @@ -2044,6 +4095,18 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "tracing-appender" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3566e8ce28cc0a3fe42519fc80e6b4c943cc4c8cef275620eb8dac2d3d4e06cf" +dependencies = [ + "crossbeam-channel", + "thiserror", + "time", + "tracing-subscriber", +] + [[package]] name = "tracing-core" version = "0.1.32" @@ -2051,6 +4114,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "nu-ansi-term", + "sharded-slab", + "smallvec", + "thread_local", + "tracing-core", + "tracing-log", ] [[package]] @@ -2121,6 +4210,18 @@ version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +[[package]] +name = "unicode-width" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + [[package]] name = "unsafe-any-ors" version = "1.0.0" @@ -2136,6 +4237,31 @@ version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "ureq" +version = "2.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11f214ce18d8b2cbe84ed3aa6486ed3f5b285cf8d8fbdbce9f3f767a724adc35" +dependencies = [ + "base64", + "flate2", + "log", + "once_cell", + "rustls", + "rustls-pki-types", + "rustls-webpki", + "serde", + "serde_json", + "url", + "webpki-roots", +] + [[package]] name = "url" version = "2.5.0" @@ -2160,9 +4286,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" dependencies = [ "getrandom", + "rand", "serde", ] +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "vcpkg" version = "0.2.15" @@ -2175,6 +4308,16 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "want" version = "0.3.1" @@ -2211,7 +4354,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", "wasm-bindgen-shared", ] @@ -2245,7 +4388,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2258,14 +4401,147 @@ checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "web-sys" -version = "0.3.69" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" dependencies = [ "js-sys", "wasm-bindgen", ] +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-roots" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3de34ae270483955a94f4b21bdaaeb83d508bb84a01435f393818edb0012009" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "weezl" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" + +[[package]] +name = "wgpu" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30e7d227c9f961f2061c26f4cb0fbd4df0ef37e056edd0931783599d6c94ef24" +dependencies = [ + "arrayvec", + "cfg-if", + "flume", + "js-sys", + "log", + "naga", + "parking_lot", + "profiling", + "raw-window-handle", + "smallvec", + "static_assertions", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "wgpu-core", + "wgpu-hal", + "wgpu-types", +] + +[[package]] +name = "wgpu-core" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef91c1d62d1e9e81c79e600131a258edf75c9531cbdbde09c44a011a47312726" +dependencies = [ + "arrayvec", + "bit-vec", + "bitflags 2.5.0", + "codespan-reporting", + "log", + "naga", + "parking_lot", + "profiling", + "raw-window-handle", + "rustc-hash", + "smallvec", + "thiserror", + "web-sys", + "wgpu-hal", + "wgpu-types", +] + +[[package]] +name = "wgpu-hal" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b84ecc802da3eb67b4cf3dd9ea6fe45bbb47ef13e6c49c5c3240868a9cc6cdd9" +dependencies = [ + "android_system_properties", + "arrayvec", + "ash", + "bit-set", + "bitflags 2.5.0", + "block", + "core-graphics-types", + "d3d12", + "glow", + "glutin_wgl_sys", + "gpu-alloc", + "gpu-allocator", + "gpu-descriptor", + "hassle-rs", + "js-sys", + "khronos-egl", + "libc", + "libloading 0.8.3", + "log", + "metal", + "naga", + "objc", + "once_cell", + "parking_lot", + "profiling", + "range-alloc", + "raw-window-handle", + "renderdoc-sys", + "rustc-hash", + "smallvec", + "thiserror", + "wasm-bindgen", + "web-sys", + "wgpu-types", + "winapi", +] + +[[package]] +name = "wgpu-types" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d5ed5f0edf0de351fe311c53304986315ce866f394a2e6df0c4b3c70774bcdd" +dependencies = [ + "bitflags 2.5.0", + "js-sys", + "web-sys", +] + +[[package]] +name = "widestring" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "653f141f39ec16bba3c5abe400a0c60da7468261cc2cbf36805022876bc721a8" + [[package]] name = "winapi" version = "0.3.9" @@ -2282,12 +4558,40 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +dependencies = [ + "winapi", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows" +version = "0.51.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca229916c5ee38c2f2bc1e9d8f04df975b4bd93f9955dc69fabb5d91270045c9" +dependencies = [ + "windows-core 0.51.1", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-core" +version = "0.51.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" +dependencies = [ + "windows-targets 0.48.5", +] + [[package]] name = "windows-core" version = "0.52.0" @@ -2438,3 +4742,150 @@ dependencies = [ "cfg-if", "windows-sys 0.48.0", ] + +[[package]] +name = "wrapcenum-derive" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a76ff259533532054cfbaefb115c613203c73707017459206380f03b3b3f266e" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.55", +] + +[[package]] +name = "xml-rs" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fcb9cbac069e033553e8bb871be2fbdffcab578eb25bd0f7c508cedc6dcd75a" + +[[package]] +name = "yoke" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65e71b2e4f287f467794c671e2b8f8a5f3716b3c829079a1c44740148eff07e4" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e6936f0cce458098a201c245a11bef556c6a0181129c7034d10d76d1ec3a2b8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.55", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.55", +] + +[[package]] +name = "zerofrom" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "655b0814c5c0b19ade497851070c640773304939a6c0fd5f5fb43da0696d05b7" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6a647510471d372f2e6c2e6b7219e44d8c574d24fdc11c610a61455782f18c3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.55", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" + +[[package]] +name = "zip" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" +dependencies = [ + "aes", + "byteorder", + "bzip2", + "constant_time_eq", + "crc32fast", + "crossbeam-utils", + "flate2", + "hmac", + "pbkdf2", + "sha1", + "time", + "zstd", +] + +[[package]] +name = "zstd" +version = "0.11.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "5.0.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.10+zstd.1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c253a4914af5bafc8fa8c86ee400827e83cf6ec01195ec1f1ed8441bf00d65aa" +dependencies = [ + "cc", + "pkg-config", +] + +[[package]] +name = "zune-inflate" +version = "0.2.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" +dependencies = [ + "simd-adler32", +] diff --git a/Cargo.toml b/Cargo.toml index ce1bd61..4d5abc1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,10 @@ path = "src/lib/qrust/mod.rs" name = "qrust" path = "src/bin/qrust/mod.rs" +[[bin]] +name = "trainer" +path = "src/bin/trainer/mod.rs" + [profile.release] panic = 'abort' strip = true @@ -70,7 +74,14 @@ lazy_static = "1.4.0" nonempty = { version = "0.10.0", features = [ "serialize", ] } +rand = "0.8.5" +rayon = "1.9.0" +burn = { version = "0.12.1", features = [ + "wgpu", + "cuda", + "tui", + "train", +] } [dev-dependencies] -claims = "0.7.1" serde_test = "1.0.176" diff --git a/src/bin/qrust/threads/clock.rs b/src/bin/qrust/threads/clock.rs index 2829573..bf6f32c 100644 --- a/src/bin/qrust/threads/clock.rs +++ b/src/bin/qrust/threads/clock.rs @@ -9,9 +9,9 @@ use qrust::{ utils::{backoff, duration_until}, }; use std::sync::Arc; -use time::OffsetDateTime; use tokio::{join, sync::mpsc, time::sleep}; +#[derive(PartialEq, Eq)] pub enum Status { Open, Closed, @@ -19,21 +19,16 @@ pub enum Status { pub struct Message { pub status: Status, - pub next_switch: OffsetDateTime, } impl From for Message { fn from(clock: types::alpaca::api::incoming::clock::Clock) -> Self { - if clock.is_open { - Self { - status: Status::Open, - next_switch: clock.next_close, - } - } else { - Self { - status: Status::Closed, - next_switch: clock.next_open, - } + Self { + status: if clock.is_open { + Status::Open + } else { + Status::Closed + }, } } } diff --git a/src/bin/qrust/threads/data/mod.rs b/src/bin/qrust/threads/data/mod.rs index 5814564..7e4827e 100644 --- a/src/bin/qrust/threads/data/mod.rs +++ b/src/bin/qrust/threads/data/mod.rs @@ -86,12 +86,13 @@ pub async fn run( message, )); } - Some(_) = clock_receiver.recv() => { + Some(message) = clock_receiver.recv() => { spawn(handle_clock_message( config.clone(), bars_us_equity_backfill_sender.clone(), bars_crypto_backfill_sender.clone(), news_backfill_sender.clone(), + message, )); } else => panic!("Communication channel unexpectedly closed.") @@ -125,7 +126,7 @@ fn init_thread( let websocket_handler = match thread_type { ThreadType::Bars(_) => websocket::bars::create_handler(config, thread_type), - ThreadType::News => websocket::news::create_handler(config), + ThreadType::News => websocket::news::create_handler(&config), }; let (websocket_sender, websocket_receiver) = mpsc::channel(100); @@ -322,13 +323,16 @@ async fn handle_clock_message( bars_us_equity_backfill_sender: mpsc::Sender, bars_crypto_backfill_sender: mpsc::Sender, news_backfill_sender: mpsc::Sender, + message: clock::Message, ) { - database::cleanup_all( - &config.clickhouse_client, - &config.clickhouse_concurrency_limiter, - ) - .await - .unwrap(); + if message.status == clock::Status::Closed { + database::cleanup_all( + &config.clickhouse_client, + &config.clickhouse_concurrency_limiter, + ) + .await + .unwrap(); + } let assets = database::assets::select( &config.clickhouse_client, diff --git a/src/bin/qrust/threads/data/websocket/news.rs b/src/bin/qrust/threads/data/websocket/news.rs index dff8762..5121d81 100644 --- a/src/bin/qrust/threads/data/websocket/news.rs +++ b/src/bin/qrust/threads/data/websocket/news.rs @@ -12,7 +12,6 @@ use std::{collections::HashMap, sync::Arc}; use tokio::sync::{Mutex, RwLock}; pub struct Handler { - pub config: Arc, pub inserter: Arc>>, } @@ -102,7 +101,7 @@ impl super::Handler for Handler { } } -pub fn create_handler(config: Arc) -> Box { +pub fn create_handler(config: &Arc) -> Box { let inserter = Arc::new(Mutex::new( config .clickhouse_client @@ -112,5 +111,5 @@ pub fn create_handler(config: Arc) -> Box { .with_max_entries((*CLICKHOUSE_BATCH_NEWS_SIZE).try_into().unwrap()), )); - Box::new(Handler { config, inserter }) + Box::new(Handler { inserter }) } diff --git a/src/bin/trainer/mod.rs b/src/bin/trainer/mod.rs new file mode 100644 index 0000000..8911dcf --- /dev/null +++ b/src/bin/trainer/mod.rs @@ -0,0 +1,133 @@ +#![warn(clippy::all, clippy::pedantic, clippy::nursery)] + +use burn::{ + config::Config, + data::{ + dataloader::{DataLoaderBuilder, Dataset}, + dataset::transform::{PartialDataset, ShuffledDataset}, + }, + module::Module, + optim::AdamConfig, + record::CompactRecorder, + tensor::backend::AutodiffBackend, + train::LearnerBuilder, +}; +use dotenv::dotenv; +use log::info; +use qrust::{ + database, + ml::{ + BarWindow, BarWindowBatcher, ModelConfig, MultipleSymbolDataset, MyAutodiffBackend, DEVICE, + }, + types::Bar, +}; +use std::{env, fs, path::Path, sync::Arc}; +use tokio::sync::Semaphore; + +#[derive(Config)] +pub struct TrainingConfig { + pub model: ModelConfig, + pub optimizer: AdamConfig, + #[config(default = 100)] + pub epochs: usize, + #[config(default = 256)] + pub batch_size: usize, + #[config(default = 16)] + pub num_workers: usize, + #[config(default = 0)] + pub seed: u64, + #[config(default = 0.2)] + pub valid_pct: f64, + #[config(default = 1.0e-4)] + pub learning_rate: f64, +} + +#[tokio::main] +async fn main() { + dotenv().ok(); + let dir = Path::new(file!()).parent().unwrap(); + + let model_config = ModelConfig::new(); + let optimizer = AdamConfig::new(); + + let training_config = TrainingConfig::new(model_config, optimizer); + + let clickhouse_client = clickhouse::Client::default() + .with_url(env::var("CLICKHOUSE_URL").expect("CLICKHOUSE_URL must be set.")) + .with_user(env::var("CLICKHOUSE_USER").expect("CLICKHOUSE_USER must be set.")) + .with_password(env::var("CLICKHOUSE_PASSWORD").expect("CLICKHOUSE_PASSWORD must be set.")) + .with_database(env::var("CLICKHOUSE_DB").expect("CLICKHOUSE_DB must be set.")); + + let clickhouse_concurrency_limiter = Arc::new(Semaphore::new(Semaphore::MAX_PERMITS)); + + let bars = database::ta::select(&clickhouse_client, &clickhouse_concurrency_limiter) + .await + .unwrap(); + + info!("Loaded {} bars.", bars.len()); + + train::( + bars, + &training_config, + dir.join("artifacts").to_str().unwrap(), + &DEVICE, + ); +} + +#[allow(clippy::cast_possible_truncation)] +#[allow(clippy::cast_sign_loss)] +#[allow(clippy::cast_precision_loss)] +fn train>( + bars: Vec, + config: &TrainingConfig, + dir: &str, + device: &B::Device, +) { + B::seed(config.seed); + + fs::create_dir_all(dir).unwrap(); + + let dataset = MultipleSymbolDataset::new(bars); + let dataset = ShuffledDataset::with_seed(dataset, config.seed); + let dataset = Arc::new(dataset); + + let split = (dataset.len() as f64 * (1.0 - config.valid_pct)) as usize; + + let train: PartialDataset>, BarWindow> = + PartialDataset::new(dataset.clone(), 0, split); + + let batcher_train = BarWindowBatcher:: { + device: device.clone(), + }; + + let dataloader_train = DataLoaderBuilder::new(batcher_train) + .batch_size(config.batch_size) + .num_workers(config.num_workers) + .build(train); + + let valid: PartialDataset>, BarWindow> = + PartialDataset::new(dataset.clone(), split, dataset.len()); + + let batcher_valid = BarWindowBatcher:: { + device: device.clone(), + }; + + let dataloader_valid = DataLoaderBuilder::new(batcher_valid) + .batch_size(config.batch_size) + .num_workers(config.num_workers) + .build(valid); + + let learner = LearnerBuilder::new(dir) + .with_file_checkpointer(CompactRecorder::new()) + .devices(vec![device.clone()]) + .num_epochs(config.epochs) + .build( + config.model.init::(device), + config.optimizer.init(), + config.learning_rate, + ); + + let trained = learner.fit(dataloader_train, dataloader_valid); + + trained.save_file(dir, &CompactRecorder::new()).unwrap(); +} diff --git a/src/lib/qrust/database/mod.rs b/src/lib/qrust/database/mod.rs index 247de1d..00a466a 100644 --- a/src/lib/qrust/database/mod.rs +++ b/src/lib/qrust/database/mod.rs @@ -5,6 +5,7 @@ pub mod bars; pub mod calendar; pub mod news; pub mod orders; +pub mod ta; use clickhouse::{error::Error, Client}; use tokio::try_join; diff --git a/src/lib/qrust/database/ta.rs b/src/lib/qrust/database/ta.rs new file mode 100644 index 0000000..552c569 --- /dev/null +++ b/src/lib/qrust/database/ta.rs @@ -0,0 +1,30 @@ +use crate::types::Bar; +use clickhouse::{error::Error, Client}; +use std::sync::Arc; +use tokio::sync::Semaphore; + +pub async fn select( + client: &Client, + concurrency_limiter: &Arc, +) -> Result, Error> { + let _ = concurrency_limiter.acquire().await.unwrap(); + client + .query( + " + SELECT symbol, + toStartOfHour(bars.time) AS time, + any(bars.open) AS open, + max(bars.high) AS high, + min(bars.low) AS low, + anyLast(bars.close) AS close, + sum(bars.volume) AS volume, + sum(bars.trades) AS trades + FROM bars FINAL + GROUP BY ALL + ORDER BY symbol, + time + ", + ) + .fetch_all::() + .await +} diff --git a/src/lib/qrust/ml/batcher.rs b/src/lib/qrust/ml/batcher.rs new file mode 100644 index 0000000..6fda083 --- /dev/null +++ b/src/lib/qrust/ml/batcher.rs @@ -0,0 +1,74 @@ +use super::BarWindow; +use burn::{ + data::dataloader::batcher::Batcher, + tensor::{self, backend::Backend, Tensor}, +}; +use rayon::iter::{IntoParallelIterator, ParallelIterator}; + +pub struct BarWindowBatcher { + pub device: B::Device, +} + +#[derive(Clone, Debug)] +pub struct BarWindowBatch { + pub hour_tensor: Tensor, + pub day_tensor: Tensor, + pub numerical_tensor: Tensor, + pub target_tensor: Tensor, +} + +impl> Batcher> + for BarWindowBatcher +{ + fn batch(&self, items: Vec) -> BarWindowBatch { + let batch_size = items.len(); + + let (hour_tensors, day_tensors, numerical_tensors, target_tensors) = items + .into_par_iter() + .fold( + || { + ( + Vec::with_capacity(batch_size), + Vec::with_capacity(batch_size), + Vec::with_capacity(batch_size), + Vec::with_capacity(batch_size), + ) + }, + |(mut hour_tensors, mut day_tensors, mut numerical_tensors, mut target_tensors), + item| { + hour_tensors.push(Tensor::from_data(item.hours, &self.device)); + day_tensors.push(Tensor::from_data(item.days, &self.device)); + numerical_tensors.push(Tensor::from_data(item.numerical, &self.device)); + target_tensors.push(Tensor::from_data(item.target, &self.device)); + + (hour_tensors, day_tensors, numerical_tensors, target_tensors) + }, + ) + .reduce( + || { + ( + Vec::with_capacity(batch_size), + Vec::with_capacity(batch_size), + Vec::with_capacity(batch_size), + Vec::with_capacity(batch_size), + ) + }, + |(mut hour_tensors, mut day_tensors, mut numerical_tensors, mut target_tensors), + item| { + hour_tensors.extend(item.0); + day_tensors.extend(item.1); + numerical_tensors.extend(item.2); + target_tensors.extend(item.3); + + (hour_tensors, day_tensors, numerical_tensors, target_tensors) + }, + ); + + BarWindowBatch { + hour_tensor: Tensor::stack(hour_tensors, 0).to_device(&self.device), + day_tensor: Tensor::stack(day_tensors, 0).to_device(&self.device), + numerical_tensor: Tensor::stack(numerical_tensors, 0).to_device(&self.device), + target_tensor: Tensor::stack(target_tensors, 0).to_device(&self.device), + } + } +} diff --git a/src/lib/qrust/ml/dataset.rs b/src/lib/qrust/ml/dataset.rs new file mode 100644 index 0000000..c3a3776 --- /dev/null +++ b/src/lib/qrust/ml/dataset.rs @@ -0,0 +1,245 @@ +use crate::types::{ + ta::{calculate_indicators, HEAD_SIZE, NUMERICAL_FIELD_COUNT}, + Bar, +}; +use burn::{ + data::dataset::{transform::ComposedDataset, Dataset}, + tensor::Data, +}; +use itertools::Itertools; + +pub const WINDOW_SIZE: usize = 48; + +#[derive(Clone, Debug)] +pub struct BarWindow { + pub hours: Data, + pub days: Data, + pub numerical: Data, + pub target: Data, +} + +#[derive(Clone, Debug)] +struct SingleSymbolDataset { + hours: Vec, + days: Vec, + numerical: Vec<[f32; NUMERICAL_FIELD_COUNT]>, + targets: Vec, +} + +impl SingleSymbolDataset { + #[allow(clippy::cast_possible_truncation)] + pub fn new(bars: Vec) -> Self { + let bars = calculate_indicators(&bars); + + let (hours, days, numerical, targets) = bars.windows(2).skip(HEAD_SIZE - 1).fold( + ( + Vec::with_capacity(bars.len() - 1), + Vec::with_capacity(bars.len() - 1), + Vec::with_capacity(bars.len() - 1), + Vec::with_capacity(bars.len() - 1), + ), + |(mut hours, mut days, mut numerical, mut targets), bar| { + hours.push(i32::from(bar[0].hour)); + days.push(i32::from(bar[0].day)); + numerical.push([ + bar[0].open as f32, + (bar[0].open_pct as f32).min(f32::MAX), + bar[0].high as f32, + (bar[0].high_pct as f32).min(f32::MAX), + bar[0].low as f32, + (bar[0].low_pct as f32).min(f32::MAX), + bar[0].close as f32, + (bar[0].close_pct as f32).min(f32::MAX), + bar[0].volume as f32, + (bar[0].volume_pct as f32).min(f32::MAX), + bar[0].trades as f32, + (bar[0].trades_pct as f32).min(f32::MAX), + bar[0].close_deriv as f32, + (bar[0].close_deriv_pct as f32).min(f32::MAX), + bar[0].sma_3 as f32, + (bar[0].sma_3_pct as f32).min(f32::MAX), + bar[0].sma_6 as f32, + (bar[0].sma_6_pct as f32).min(f32::MAX), + bar[0].sma_12 as f32, + (bar[0].sma_12_pct as f32).min(f32::MAX), + bar[0].sma_24 as f32, + (bar[0].sma_24_pct as f32).min(f32::MAX), + bar[0].sma_48 as f32, + (bar[0].sma_48_pct as f32).min(f32::MAX), + bar[0].sma_72 as f32, + (bar[0].sma_72_pct as f32).min(f32::MAX), + bar[0].ema_3 as f32, + (bar[0].ema_3_pct as f32).min(f32::MAX), + bar[0].ema_6 as f32, + (bar[0].ema_6_pct as f32).min(f32::MAX), + bar[0].ema_12 as f32, + (bar[0].ema_12_pct as f32).min(f32::MAX), + bar[0].ema_24 as f32, + (bar[0].ema_24_pct as f32).min(f32::MAX), + bar[0].ema_48 as f32, + (bar[0].ema_48_pct as f32).min(f32::MAX), + bar[0].ema_72 as f32, + (bar[0].ema_72_pct as f32).min(f32::MAX), + bar[0].macd as f32, + (bar[0].macd_pct as f32).min(f32::MAX), + bar[0].macd_signal as f32, + (bar[0].macd_signal_pct as f32).min(f32::MAX), + bar[0].obv as f32, + (bar[0].obv_pct as f32).min(f32::MAX), + bar[0].rsi as f32, + (bar[0].rsi_pct as f32).min(f32::MAX), + bar[0].bbands_lower as f32, + (bar[0].bbands_lower_pct as f32).min(f32::MAX), + bar[0].bbands_mean as f32, + (bar[0].bbands_mean_pct as f32).min(f32::MAX), + bar[0].bbands_upper as f32, + (bar[0].bbands_upper_pct as f32).min(f32::MAX), + ]); + targets.push(bar[1].close as f32); + (hours, days, numerical, targets) + }, + ); + + Self { + hours, + days, + numerical, + targets, + } + } +} + +impl Dataset for SingleSymbolDataset { + fn len(&self) -> usize { + self.targets.len() - WINDOW_SIZE + 1 + } + + #[allow(clippy::single_range_in_vec_init)] + fn get(&self, idx: usize) -> Option { + if idx >= self.len() { + return None; + } + + let hours: [i32; WINDOW_SIZE] = self.hours[idx..idx + WINDOW_SIZE].try_into().unwrap(); + let days: [i32; WINDOW_SIZE] = self.days[idx..idx + WINDOW_SIZE].try_into().unwrap(); + let numerical: [[f32; NUMERICAL_FIELD_COUNT]; WINDOW_SIZE] = + self.numerical[idx..idx + WINDOW_SIZE].try_into().unwrap(); + let target: [f32; 1] = [self.targets[idx + WINDOW_SIZE - 1]]; + + Some(BarWindow { + hours: Data::from(hours), + days: Data::from(days), + numerical: Data::from(numerical), + target: Data::from(target), + }) + } +} + +pub struct MultipleSymbolDataset { + composed_dataset: ComposedDataset, +} + +impl MultipleSymbolDataset { + pub fn new(bars: Vec) -> Self { + let groups = bars + .into_iter() + .group_by(|bar| bar.symbol.clone()) + .into_iter() + .map(|(_, group)| group.collect::>()) + .map(SingleSymbolDataset::new) + .collect(); + + Self { + composed_dataset: ComposedDataset::new(groups), + } + } +} + +impl Dataset for MultipleSymbolDataset { + fn len(&self) -> usize { + self.composed_dataset.len() + } + + fn get(&self, idx: usize) -> Option { + self.composed_dataset.get(idx) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use rand::{ + distributions::{Distribution, Uniform}, + Rng, + }; + use time::OffsetDateTime; + + fn generate_random_dataset(length: usize) -> SingleSymbolDataset { + let mut rng = rand::thread_rng(); + let uniform = Uniform::new(1.0, 100.0); + let mut bars = Vec::with_capacity(length); + + for _ in 0..=(length + (HEAD_SIZE - 1) + (WINDOW_SIZE - 1)) { + bars.push(Bar { + symbol: "AAPL".to_string(), + time: OffsetDateTime::now_utc(), + open: uniform.sample(&mut rng), + high: uniform.sample(&mut rng), + low: uniform.sample(&mut rng), + close: uniform.sample(&mut rng), + volume: uniform.sample(&mut rng), + trades: rng.gen_range(1..100), + }); + } + + SingleSymbolDataset::new(bars) + } + + #[test] + fn test_single_symbol_dataset() { + let length = 100; + let dataset = generate_random_dataset(length); + + assert_eq!(dataset.len(), length); + } + + #[test] + fn test_single_symbol_dataset_window() { + let length = 100; + let dataset = generate_random_dataset(length); + + let item = dataset.get(0).unwrap(); + + assert_eq!(item.hours.shape.dims, [WINDOW_SIZE]); + assert_eq!(item.days.shape.dims, [WINDOW_SIZE]); + assert_eq!( + item.numerical.shape.dims, + [WINDOW_SIZE, NUMERICAL_FIELD_COUNT] + ); + assert_eq!(item.target.shape.dims, [1]); + } + + #[test] + fn test_single_symbol_dataset_last_window() { + let length = 100; + let dataset = generate_random_dataset(length); + + let item = dataset.get(dataset.len() - 1).unwrap(); + + assert_eq!(item.hours.shape.dims, [WINDOW_SIZE]); + assert_eq!(item.days.shape.dims, [WINDOW_SIZE]); + assert_eq!( + item.numerical.shape.dims, + [WINDOW_SIZE, NUMERICAL_FIELD_COUNT] + ); + assert_eq!(item.target.shape.dims, [1]); + } + + #[test] + fn test_single_symbol_dataset_out_of_bounds() { + let length = 100; + let dataset = generate_random_dataset(length); + + assert!(dataset.get(dataset.len()).is_none()); + } +} diff --git a/src/lib/qrust/ml/mod.rs b/src/lib/qrust/ml/mod.rs new file mode 100644 index 0000000..de44f44 --- /dev/null +++ b/src/lib/qrust/ml/mod.rs @@ -0,0 +1,21 @@ +pub mod batcher; +pub mod dataset; +pub mod model; + +pub use batcher::{BarWindowBatch, BarWindowBatcher}; +pub use dataset::{BarWindow, MultipleSymbolDataset}; +pub use model::{Model, ModelConfig}; + +use burn::{ + backend::{ + wgpu::{AutoGraphicsApi, WgpuDevice}, + Autodiff, Wgpu, + }, + tensor::backend::Backend, +}; + +pub type MyBackend = Wgpu; +pub type MyAutodiffBackend = Autodiff; +pub type MyDevice = as Backend>::Device; + +pub const DEVICE: MyDevice = WgpuDevice::BestAvailable; diff --git a/src/lib/qrust/ml/model.rs b/src/lib/qrust/ml/model.rs new file mode 100644 index 0000000..519dd87 --- /dev/null +++ b/src/lib/qrust/ml/model.rs @@ -0,0 +1,160 @@ +use super::BarWindowBatch; +use crate::types::ta::NUMERICAL_FIELD_COUNT; +use burn::{ + config::Config, + module::Module, + nn::{ + loss::{MSELoss, Reduction}, + Dropout, DropoutConfig, Embedding, EmbeddingConfig, Linear, LinearConfig, Lstm, LstmConfig, + }, + tensor::{ + self, + backend::{AutodiffBackend, Backend}, + Tensor, + }, + train::{RegressionOutput, TrainOutput, TrainStep, ValidStep}, +}; + +#[derive(Module, Debug)] +pub struct Model { + hour_embedding: Embedding, + day_embedding: Embedding, + lstm_1: Lstm, + dropout_1: Dropout, + lstm_2: Lstm, + dropout_2: Dropout, + lstm_3: Lstm, + dropout_3: Dropout, + lstm_4: Lstm, + dropout_4: Dropout, + linear: Linear, +} + +#[derive(Config, Debug)] +pub struct ModelConfig { + #[config(default = "3")] + pub hour_features: usize, + #[config(default = "2")] + pub day_features: usize, + #[config(default = "{NUMERICAL_FIELD_COUNT}")] + pub numerical_features: usize, + #[config(default = "0.2")] + pub dropout: f64, +} + +impl ModelConfig { + pub fn init(&self, device: &B::Device) -> Model { + let num_features = self.numerical_features + self.hour_features + self.day_features; + + let lstm_1_hidden_size = 512; + let lstm_2_hidden_size = 256; + let lstm_3_hidden_size = 64; + let lstm_4_hidden_size = 32; + + Model { + hour_embedding: EmbeddingConfig::new(24, self.hour_features).init(device), + day_embedding: EmbeddingConfig::new(7, self.day_features).init(device), + lstm_1: LstmConfig::new(num_features, lstm_1_hidden_size, true).init(device), + dropout_1: DropoutConfig::new(self.dropout).init(), + lstm_2: LstmConfig::new(lstm_1_hidden_size, lstm_2_hidden_size, true).init(device), + dropout_2: DropoutConfig::new(self.dropout).init(), + lstm_3: LstmConfig::new(lstm_2_hidden_size, lstm_3_hidden_size, true).init(device), + dropout_3: DropoutConfig::new(self.dropout).init(), + lstm_4: LstmConfig::new(lstm_3_hidden_size, lstm_4_hidden_size, true).init(device), + dropout_4: DropoutConfig::new(self.dropout).init(), + linear: LinearConfig::new(lstm_4_hidden_size, 1).init(device), + } + } +} + +impl Model { + pub fn forward( + &self, + hour: Tensor, + day: Tensor, + numerical: Tensor, + ) -> Tensor { + let hour = self.hour_embedding.forward(hour); + let day = self.day_embedding.forward(day); + + let x = Tensor::cat(vec![hour, day, numerical], 2); + + let (x, _) = self.lstm_1.forward(x, None); + let x = self.dropout_1.forward(x); + let (x, _) = self.lstm_2.forward(x, None); + let x = self.dropout_2.forward(x); + let (x, _) = self.lstm_3.forward(x, None); + let x = self.dropout_3.forward(x); + let (x, _) = self.lstm_4.forward(x, None); + let x = self.dropout_4.forward(x); + + let [batch_size, window_size, features] = x.shape().dims; + + let x = x.slice([0..batch_size, window_size - 1..window_size, 0..features]); + let x = x.squeeze(1); + + self.linear.forward(x) + } + + pub fn forward_regression( + &self, + hour: Tensor, + day: Tensor, + numerical: Tensor, + target: Tensor, + ) -> RegressionOutput { + let output = self.forward(hour, day, numerical); + let loss = MSELoss::new().forward(output.clone(), target.clone(), Reduction::Mean); + + RegressionOutput::new(loss, output, target) + } +} + +impl TrainStep, RegressionOutput> for Model { + fn step(&self, batch: BarWindowBatch) -> TrainOutput> { + let item = self.forward_regression( + batch.hour_tensor, + batch.day_tensor, + batch.numerical_tensor, + batch.target_tensor, + ); + + TrainOutput::new(self, item.loss.backward(), item) + } +} + +impl ValidStep, RegressionOutput> for Model { + fn step(&self, batch: BarWindowBatch) -> RegressionOutput { + self.forward_regression( + batch.hour_tensor, + batch.day_tensor, + batch.numerical_tensor, + batch.target_tensor, + ) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use burn::{backend::Wgpu, tensor::Distribution}; + + #[test] + #[ignore] + fn test_model() { + let device = Default::default(); + let distribution = Distribution::Normal(0.0, 1.0); + + let config = ModelConfig::new().with_numerical_features(7); + + let model = config.init::(&device); + + let hour = Tensor::ones([2, 10], &device); + let day = Tensor::ones([2, 10], &device); + let numerical = Tensor::random([2, 10, 7], distribution, &device); + + let output = model.forward(hour, day, numerical); + + assert_eq!(output.shape().dims, [2, 1]); + } +} diff --git a/src/lib/qrust/mod.rs b/src/lib/qrust/mod.rs index 4fb7569..2c5e950 100644 --- a/src/lib/qrust/mod.rs +++ b/src/lib/qrust/mod.rs @@ -1,4 +1,6 @@ pub mod alpaca; pub mod database; +pub mod ml; +pub mod ta; pub mod types; pub mod utils; diff --git a/src/lib/qrust/ta/bbands.rs b/src/lib/qrust/ta/bbands.rs new file mode 100644 index 0000000..93636d1 --- /dev/null +++ b/src/lib/qrust/ta/bbands.rs @@ -0,0 +1,149 @@ +use std::{borrow::Borrow, collections::VecDeque, iter::Scan, num::NonZeroUsize}; + +pub struct BbandsState { + window: VecDeque, + sum: f64, + squared_sum: f64, + multiplier: f64, +} + +#[allow(clippy::type_complexity)] +pub trait Bbands: Iterator + Sized { + fn bbands( + self, + period: NonZeroUsize, + multiplier: f64, // Typically 2.0 + ) -> Scan Option<(f64, f64, f64)>>; +} + +impl Bbands for I +where + I: Iterator, + T: Borrow, +{ + fn bbands( + self, + period: NonZeroUsize, + multiplier: f64, + ) -> Scan Option<(f64, f64, f64)>> { + self.scan( + BbandsState { + window: VecDeque::from(vec![0.0; period.get()]), + sum: 0.0, + squared_sum: 0.0, + multiplier, + }, + |state: &mut BbandsState, value: T| { + let value = *value.borrow(); + + let front = state.window.pop_front().unwrap(); + state.sum -= front; + state.squared_sum -= front.powi(2); + + state.window.push_back(value); + state.sum += value; + state.squared_sum += value.powi(2); + + let mean = state.sum / state.window.len() as f64; + let variance = + ((state.squared_sum / state.window.len() as f64) - mean.powi(2)).max(0.0); + let standard_deviation = variance.sqrt(); + + let upper_band = mean + state.multiplier * standard_deviation; + let lower_band = mean - state.multiplier * standard_deviation; + + Some((upper_band, mean, lower_band)) + }, + ) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_bbands() { + let data = vec![1.0, 2.0, 3.0, 4.0, 5.0]; + let bbands = data + .into_iter() + .bbands(NonZeroUsize::new(3).unwrap(), 2.0) + .map(|(upper, mean, lower)| { + ( + (upper * 100.0).round() / 100.0, + (mean * 100.0).round() / 100.0, + (lower * 100.0).round() / 100.0, + ) + }) + .collect::>(); + + assert_eq!( + bbands, + vec![ + (1.28, 0.33, -0.61), + (2.63, 1.0, -0.63), + (3.63, 2.0, 0.37), + (4.63, 3.0, 1.37), + (5.63, 4.0, 2.37) + ] + ); + } + + #[test] + fn test_bbands_empty() { + let data = Vec::::new(); + let bbands = data + .into_iter() + .bbands(NonZeroUsize::new(3).unwrap(), 2.0) + .collect::>(); + + assert_eq!(bbands, Vec::<(f64, f64, f64)>::new()); + } + + #[test] + fn test_bbands_1_period() { + let data = vec![1.0, 2.0, 3.0, 4.0, 5.0]; + let bbands = data + .into_iter() + .bbands(NonZeroUsize::new(1).unwrap(), 2.0) + .collect::>(); + + assert_eq!( + bbands, + vec![ + (1.0, 1.0, 1.0), + (2.0, 2.0, 2.0), + (3.0, 3.0, 3.0), + (4.0, 4.0, 4.0), + (5.0, 5.0, 5.0) + ] + ); + } + + #[test] + fn test_bbands_borrow() { + let data = [1.0, 2.0, 3.0, 4.0, 5.0]; + let bbands = data + .iter() + .bbands(NonZeroUsize::new(3).unwrap(), 2.0) + .map(|(upper, mean, lower)| { + ( + (upper * 100.0).round() / 100.0, + (mean * 100.0).round() / 100.0, + (lower * 100.0).round() / 100.0, + ) + }) + .collect::>(); + + assert_eq!( + bbands, + vec![ + (1.28, 0.33, -0.61), + (2.63, 1.0, -0.63), + (3.63, 2.0, 0.37), + (4.63, 3.0, 1.37), + (5.63, 4.0, 2.37) + ] + ); + } +} diff --git a/src/lib/qrust/ta/deriv.rs b/src/lib/qrust/ta/deriv.rs new file mode 100644 index 0000000..bc401c6 --- /dev/null +++ b/src/lib/qrust/ta/deriv.rs @@ -0,0 +1,59 @@ +use std::{borrow::Borrow, iter::Scan}; + +pub struct DerivState { + pub last: f64, +} + +#[allow(clippy::type_complexity)] +pub trait Deriv: Iterator + Sized { + fn deriv(self) -> Scan Option>; +} + +impl Deriv for I +where + I: Iterator, + T: Borrow, +{ + fn deriv(self) -> Scan Option> { + self.scan( + DerivState { last: 0.0 }, + |state: &mut DerivState, value: T| { + let value = *value.borrow(); + + let deriv = value - state.last; + state.last = value; + + Some(deriv) + }, + ) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_deriv() { + let data = vec![1.0, 3.0, 6.0, 3.0, 1.0]; + let deriv = data.into_iter().deriv().collect::>(); + + assert_eq!(deriv, vec![1.0, 2.0, 3.0, -3.0, -2.0]); + } + + #[test] + fn test_deriv_empty() { + let data = Vec::::new(); + let deriv = data.into_iter().deriv().collect::>(); + + assert_eq!(deriv, Vec::::new()); + } + + #[test] + fn test_deriv_borrow() { + let data = [1.0, 3.0, 6.0, 3.0, 1.0]; + let deriv = data.iter().deriv().collect::>(); + + assert_eq!(deriv, vec![1.0, 2.0, 3.0, -3.0, -2.0]); + } +} diff --git a/src/lib/qrust/ta/ema.rs b/src/lib/qrust/ta/ema.rs new file mode 100644 index 0000000..eff5781 --- /dev/null +++ b/src/lib/qrust/ta/ema.rs @@ -0,0 +1,95 @@ +use std::{ + borrow::Borrow, + iter::{Peekable, Scan}, + num::NonZeroUsize, +}; + +pub struct EmaState { + weight: f64, + ema: f64, +} + +#[allow(clippy::type_complexity)] +pub trait Ema: Iterator + Sized { + fn ema( + self, + period: NonZeroUsize, + ) -> Scan, EmaState, fn(&mut EmaState, T) -> Option>; +} + +impl Ema for I +where + I: Iterator, + T: Borrow, +{ + fn ema( + self, + period: NonZeroUsize, + ) -> Scan, EmaState, fn(&mut EmaState, T) -> Option> { + let smoothing = 2.0; + let weight = smoothing / (1.0 + period.get() as f64); + + let mut iter = self.peekable(); + let first = iter.peek().map(|value| *value.borrow()).unwrap_or_default(); + + iter.scan( + EmaState { weight, ema: first }, + |state: &mut EmaState, value: T| { + let value = *value.borrow(); + + state.ema = (value * state.weight) + (state.ema * (1.0 - state.weight)); + + Some(state.ema) + }, + ) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_ema() { + let data = vec![1.0, 2.0, 3.0, 4.0, 5.0]; + let ema = data + .into_iter() + .ema(NonZeroUsize::new(3).unwrap()) + .collect::>(); + + assert_eq!(ema, vec![1.0, 1.5, 2.25, 3.125, 4.0625]); + } + + #[test] + fn test_ema_empty() { + let data = Vec::::new(); + let ema = data + .into_iter() + .ema(NonZeroUsize::new(3).unwrap()) + .collect::>(); + + assert_eq!(ema, Vec::::new()); + } + + #[test] + fn test_ema_1_period() { + let data = vec![1.0, 2.0, 3.0, 4.0, 5.0]; + let ema = data + .into_iter() + .ema(NonZeroUsize::new(1).unwrap()) + .collect::>(); + + assert_eq!(ema, vec![1.0, 2.0, 3.0, 4.0, 5.0]); + } + + #[test] + fn test_ema_borrow() { + let data = [1.0, 2.0, 3.0, 4.0, 5.0]; + let ema = data + .iter() + .ema(NonZeroUsize::new(3).unwrap()) + .collect::>(); + + assert_eq!(ema, vec![1.0, 1.5, 2.25, 3.125, 4.0625]); + } +} diff --git a/src/lib/qrust/ta/macd.rs b/src/lib/qrust/ta/macd.rs new file mode 100644 index 0000000..3cb3655 --- /dev/null +++ b/src/lib/qrust/ta/macd.rs @@ -0,0 +1,216 @@ +use std::{ + borrow::Borrow, + iter::{Peekable, Scan}, + num::NonZeroUsize, +}; + +pub struct MacdState { + short_weight: f64, + long_weight: f64, + signal_weight: f64, + short_ema: f64, + long_ema: f64, + signal_ema: f64, +} + +#[allow(clippy::type_complexity)] +pub trait Macd: Iterator + Sized { + fn macd( + self, + short_period: NonZeroUsize, // Typically 12 + long_period: NonZeroUsize, // Typically 26 + signal_period: NonZeroUsize, // Typically 9 + ) -> Scan, MacdState, fn(&mut MacdState, T) -> Option<(f64, f64)>>; +} + +impl Macd for I +where + I: Iterator, + T: Borrow, +{ + fn macd( + self, + short_period: NonZeroUsize, + long_period: NonZeroUsize, + signal_period: NonZeroUsize, + ) -> Scan, MacdState, fn(&mut MacdState, T) -> Option<(f64, f64)>> { + let smoothing = 2.0; + let short_weight = smoothing / (1.0 + short_period.get() as f64); + let long_weight = smoothing / (1.0 + long_period.get() as f64); + let signal_weight = smoothing / (1.0 + signal_period.get() as f64); + + let mut iter = self.peekable(); + let first = iter.peek().map(|value| *value.borrow()).unwrap_or_default(); + + iter.scan( + MacdState { + short_weight, + long_weight, + signal_weight, + short_ema: first, + long_ema: first, + signal_ema: 0.0, + }, + |state: &mut MacdState, value: T| { + let value = *value.borrow(); + + state.short_ema = + (value * state.short_weight) + (state.short_ema * (1.0 - state.short_weight)); + state.long_ema = + (value * state.long_weight) + (state.long_ema * (1.0 - state.long_weight)); + + let macd = state.short_ema - state.long_ema; + state.signal_ema = + (macd * state.signal_weight) + (state.signal_ema * (1.0 - state.signal_weight)); + + Some((macd, state.signal_ema)) + }, + ) + } +} + +#[cfg(test)] +mod tests { + use super::super::ema::Ema; + use super::*; + + #[test] + fn test_macd() { + let data = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0]; + + let short_ema = data + .clone() + .into_iter() + .ema(NonZeroUsize::new(3).unwrap()) + .collect::>(); + + let long_ema = data + .clone() + .into_iter() + .ema(NonZeroUsize::new(5).unwrap()) + .collect::>(); + + let macd = short_ema + .into_iter() + .zip(long_ema) + .map(|(short, long)| short - long) + .collect::>(); + + let signal = macd + .clone() + .into_iter() + .ema(NonZeroUsize::new(3).unwrap()) + .collect::>(); + + let expected = macd.into_iter().zip(signal).collect::>(); + + assert_eq!( + data.into_iter() + .macd( + NonZeroUsize::new(3).unwrap(), + NonZeroUsize::new(5).unwrap(), + NonZeroUsize::new(3).unwrap() + ) + .collect::>(), + expected + ); + } + + #[test] + fn test_macd_empty() { + let data = Vec::::new(); + + assert_eq!( + data.into_iter() + .macd( + NonZeroUsize::new(3).unwrap(), + NonZeroUsize::new(5).unwrap(), + NonZeroUsize::new(3).unwrap() + ) + .collect::>(), + vec![] + ); + } + + #[test] + fn test_macd_1_period() { + let data = vec![1.0, 2.0, 3.0, 4.0, 5.0]; + + let short_ema = data + .clone() + .into_iter() + .ema(NonZeroUsize::new(1).unwrap()) + .collect::>(); + + let long_ema = data + .clone() + .into_iter() + .ema(NonZeroUsize::new(1).unwrap()) + .collect::>(); + + let macd = short_ema + .into_iter() + .zip(long_ema) + .map(|(short, long)| short - long) + .collect::>(); + + let signal = macd + .clone() + .into_iter() + .ema(NonZeroUsize::new(1).unwrap()) + .collect::>(); + + let expected = macd.into_iter().zip(signal).collect::>(); + + assert_eq!( + data.into_iter() + .macd( + NonZeroUsize::new(1).unwrap(), + NonZeroUsize::new(1).unwrap(), + NonZeroUsize::new(1).unwrap() + ) + .collect::>(), + expected + ); + } + + #[test] + fn test_macd_borrow() { + let data = [1.0, 2.0, 3.0, 4.0, 5.0]; + + let short_ema = data + .into_iter() + .ema(NonZeroUsize::new(3).unwrap()) + .collect::>(); + + let long_ema = data + .into_iter() + .ema(NonZeroUsize::new(5).unwrap()) + .collect::>(); + + let macd = short_ema + .into_iter() + .zip(long_ema) + .map(|(short, long)| short - long) + .collect::>(); + + let signal = macd + .clone() + .into_iter() + .ema(NonZeroUsize::new(3).unwrap()) + .collect::>(); + + let expected = macd.into_iter().zip(signal).collect::>(); + + assert_eq!( + data.iter() + .macd( + NonZeroUsize::new(3).unwrap(), + NonZeroUsize::new(5).unwrap(), + NonZeroUsize::new(3).unwrap() + ) + .collect::>(), + expected + ); + } +} diff --git a/src/lib/qrust/ta/mod.rs b/src/lib/qrust/ta/mod.rs new file mode 100644 index 0000000..d37263c --- /dev/null +++ b/src/lib/qrust/ta/mod.rs @@ -0,0 +1,17 @@ +pub mod bbands; +pub mod deriv; +pub mod ema; +pub mod macd; +pub mod obv; +pub mod pct; +pub mod rsi; +pub mod sma; + +pub use bbands::Bbands; +pub use deriv::Deriv; +pub use ema::Ema; +pub use macd::Macd; +pub use obv::Obv; +pub use pct::Pct; +pub use rsi::Rsi; +pub use sma::Sma; diff --git a/src/lib/qrust/ta/obv.rs b/src/lib/qrust/ta/obv.rs new file mode 100644 index 0000000..e208696 --- /dev/null +++ b/src/lib/qrust/ta/obv.rs @@ -0,0 +1,73 @@ +use std::{ + borrow::Borrow, + iter::{Peekable, Scan}, +}; + +pub struct ObvState { + last: f64, + obv: f64, +} + +#[allow(clippy::type_complexity)] +pub trait Obv: Iterator + Sized { + fn obv(self) -> Scan, ObvState, fn(&mut ObvState, T) -> Option>; +} + +impl Obv for I +where + I: Iterator, + T: Borrow<(f64, f64)>, +{ + fn obv(self) -> Scan, ObvState, fn(&mut ObvState, T) -> Option> { + let mut iter = self.peekable(); + let first = iter.peek().map(|value| *value.borrow()).unwrap_or_default(); + + iter.scan( + ObvState { + last: first.0, + obv: 0.0, + }, + |state: &mut ObvState, value: T| { + let (close, volume) = *value.borrow(); + + if close > state.last { + state.obv += volume; + } else if close < state.last { + state.obv -= volume; + } + state.last = close; + + Some(state.obv) + }, + ) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_obv() { + let data = vec![(1.0, 1.0), (2.0, 2.0), (3.0, 3.0), (2.0, 4.0), (1.0, 5.0)]; + let obv = data.into_iter().obv().collect::>(); + + assert_eq!(obv, vec![0.0, 2.0, 5.0, 1.0, -4.0]); + } + + #[test] + fn test_obv_empty() { + let data = Vec::<(f64, f64)>::new(); + let obv = data.into_iter().obv().collect::>(); + + assert_eq!(obv, Vec::::new()); + } + + #[test] + fn test_obv_borrow() { + let data = [(1.0, 1.0), (2.0, 2.0), (3.0, 3.0), (2.0, 4.0), (1.0, 5.0)]; + let obv = data.iter().obv().collect::>(); + + assert_eq!(obv, vec![0.0, 2.0, 5.0, 1.0, -4.0]); + } +} diff --git a/src/lib/qrust/ta/pct.rs b/src/lib/qrust/ta/pct.rs new file mode 100644 index 0000000..c552628 --- /dev/null +++ b/src/lib/qrust/ta/pct.rs @@ -0,0 +1,64 @@ +use std::{borrow::Borrow, iter::Scan}; + +pub struct PctState { + pub last: f64, +} + +#[allow(clippy::type_complexity)] +pub trait Pct: Iterator + Sized { + fn pct(self) -> Scan Option>; +} + +impl Pct for I +where + I: Iterator, + T: Borrow, +{ + fn pct(self) -> Scan Option> { + self.scan(PctState { last: 0.0 }, |state: &mut PctState, value: T| { + let value = *value.borrow(); + + let pct = value / state.last - 1.0; + state.last = value; + + Some(pct) + }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_pct() { + let data = vec![1.0, 2.0, 4.0, 2.0, 1.0]; + let pct = data.into_iter().pct().collect::>(); + + assert_eq!(pct, vec![f64::INFINITY, 1.0, 1.0, -0.5, -0.5]); + } + + #[test] + fn test_pct_empty() { + let data = Vec::::new(); + let pct = data.into_iter().pct().collect::>(); + + assert_eq!(pct, Vec::::new()); + } + + #[test] + fn test_pct_0() { + let data = vec![1.0, 0.0, 4.0, 2.0, 1.0]; + let pct = data.into_iter().pct().collect::>(); + + assert_eq!(pct, vec![f64::INFINITY, -1.0, f64::INFINITY, -0.5, -0.5]); + } + + #[test] + fn test_pct_borrow() { + let data = [1.0, 2.0, 4.0, 2.0, 1.0]; + let pct = data.iter().pct().collect::>(); + + assert_eq!(pct, vec![f64::INFINITY, 1.0, 1.0, -0.5, -0.5]); + } +} diff --git a/src/lib/qrust/ta/rsi.rs b/src/lib/qrust/ta/rsi.rs new file mode 100644 index 0000000..c99578f --- /dev/null +++ b/src/lib/qrust/ta/rsi.rs @@ -0,0 +1,135 @@ +use std::{ + borrow::Borrow, + collections::VecDeque, + iter::{Peekable, Scan}, + num::NonZeroUsize, +}; + +pub struct RsiState { + last: f64, + window_gains: VecDeque, + window_losses: VecDeque, + sum_gains: f64, + sum_losses: f64, +} + +#[allow(clippy::type_complexity)] +pub trait Rsi: Iterator + Sized { + fn rsi( + self, + period: NonZeroUsize, // Typically 14 + ) -> Scan, RsiState, fn(&mut RsiState, T) -> Option>; +} + +impl Rsi for I +where + I: Iterator, + T: Borrow, +{ + fn rsi( + self, + period: NonZeroUsize, + ) -> Scan, RsiState, fn(&mut RsiState, T) -> Option> { + let mut iter = self.peekable(); + let first = iter.peek().map(|value| *value.borrow()).unwrap_or_default(); + + iter.scan( + RsiState { + last: first, + window_gains: VecDeque::from(vec![0.0; period.get()]), + window_losses: VecDeque::from(vec![0.0; period.get()]), + sum_gains: 0.0, + sum_losses: 0.0, + }, + |state, value| { + let value = *value.borrow(); + + state.sum_gains -= state.window_gains.pop_front().unwrap(); + state.sum_losses -= state.window_losses.pop_front().unwrap(); + + let gain = (value - state.last).max(0.0); + let loss = (state.last - value).max(0.0); + + state.last = value; + + state.window_gains.push_back(gain); + state.window_losses.push_back(loss); + state.sum_gains += gain; + state.sum_losses += loss; + + let avg_loss = state.sum_losses / state.window_losses.len() as f64; + + if avg_loss == 0.0 { + return Some(100.0); + } + + let avg_gain = state.sum_gains / state.window_gains.len() as f64; + let rs = avg_gain / avg_loss; + + Some(100.0 - (100.0 / (1.0 + rs))) + }, + ) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_rsi() { + let data = vec![1.0, 4.0, 7.0, 4.0, 1.0]; + let rsi = data + .into_iter() + .rsi(NonZeroUsize::new(3).unwrap()) + .map(|v| (v * 100.0).round() / 100.0) + .collect::>(); + + assert_eq!(rsi, vec![100.0, 100.0, 100.0, 66.67, 33.33]); + } + + #[test] + fn test_rsi_empty() { + let data = Vec::::new(); + let rsi = data + .into_iter() + .rsi(NonZeroUsize::new(3).unwrap()) + .collect::>(); + + assert_eq!(rsi, Vec::::new()); + } + + #[test] + fn test_rsi_no_loss() { + let data = vec![1.0, 2.0, 3.0, 4.0, 5.0]; + let rsi = data + .into_iter() + .rsi(NonZeroUsize::new(3).unwrap()) + .collect::>(); + + assert_eq!(rsi, vec![100.0, 100.0, 100.0, 100.0, 100.0]); + } + + #[test] + fn test_rsi_no_gain() { + let data = vec![5.0, 4.0, 3.0, 2.0, 1.0]; + let rsi = data + .into_iter() + .rsi(NonZeroUsize::new(3).unwrap()) + .collect::>(); + + assert_eq!(rsi, vec![100.0, 0.0, 0.0, 0.0, 0.0]); + } + + #[test] + fn test_rsi_borrow() { + let data = [1.0, 4.0, 7.0, 4.0, 1.0]; + let rsi = data + .iter() + .rsi(NonZeroUsize::new(3).unwrap()) + .map(|v| (v * 100.0).round() / 100.0) + .collect::>(); + + assert_eq!(rsi, vec![100.0, 100.0, 100.0, 66.67, 33.33]); + } +} diff --git a/src/lib/qrust/ta/sma.rs b/src/lib/qrust/ta/sma.rs new file mode 100644 index 0000000..02159b8 --- /dev/null +++ b/src/lib/qrust/ta/sma.rs @@ -0,0 +1,88 @@ +use std::{borrow::Borrow, collections::VecDeque, iter::Scan, num::NonZeroUsize}; + +pub struct SmaState { + window: VecDeque, + sum: f64, +} + +#[allow(clippy::type_complexity)] +pub trait Sma: Iterator + Sized { + fn sma(self, period: NonZeroUsize) + -> Scan Option>; +} + +impl Sma for I +where + I: Iterator, + T: Borrow, +{ + fn sma( + self, + period: NonZeroUsize, + ) -> Scan Option> { + self.scan( + SmaState { + window: VecDeque::from(vec![0.0; period.get()]), + sum: 0.0, + }, + |state: &mut SmaState, value: T| { + let value = *value.borrow(); + + state.sum -= state.window.pop_front().unwrap(); + state.window.push_back(value); + state.sum += value; + + Some(state.sum / state.window.len() as f64) + }, + ) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_sma() { + let data = vec![3.0, 6.0, 9.0, 12.0, 15.0]; + let sma = data + .into_iter() + .sma(NonZeroUsize::new(3).unwrap()) + .collect::>(); + + assert_eq!(sma, vec![1.0, 3.0, 6.0, 9.0, 12.0]); + } + + #[test] + fn test_sma_empty() { + let data = Vec::::new(); + let sma = data + .into_iter() + .sma(NonZeroUsize::new(3).unwrap()) + .collect::>(); + + assert_eq!(sma, Vec::::new()); + } + + #[test] + fn test_sma_1_period() { + let data = vec![1.0, 2.0, 3.0, 4.0, 5.0]; + let sma = data + .into_iter() + .sma(NonZeroUsize::new(1).unwrap()) + .collect::>(); + + assert_eq!(sma, vec![1.0, 2.0, 3.0, 4.0, 5.0]); + } + + #[test] + fn test_sma_borrow() { + let data = [3.0, 6.0, 9.0, 12.0, 15.0]; + let sma = data + .iter() + .sma(NonZeroUsize::new(3).unwrap()) + .collect::>(); + + assert_eq!(sma, vec![1.0, 3.0, 6.0, 9.0, 12.0]); + } +} diff --git a/src/lib/qrust/types/mod.rs b/src/lib/qrust/types/mod.rs index b06f1ba..16a5fde 100644 --- a/src/lib/qrust/types/mod.rs +++ b/src/lib/qrust/types/mod.rs @@ -5,6 +5,7 @@ pub mod bar; pub mod calendar; pub mod news; pub mod order; +pub mod ta; pub use asset::{Asset, Class, Exchange}; pub use backfill::Backfill; diff --git a/src/lib/qrust/types/ta.rs b/src/lib/qrust/types/ta.rs new file mode 100644 index 0000000..4dd1331 --- /dev/null +++ b/src/lib/qrust/types/ta.rs @@ -0,0 +1,315 @@ +use super::Bar; +use crate::ta::{Bbands, Deriv, Ema, Macd, Obv, Pct, Rsi, Sma}; +use rayon::scope; +use serde::{Deserialize, Serialize}; +use std::num::NonZeroUsize; + +pub const HEAD_SIZE: usize = 72; +pub const FIELD_COUNT: usize = 54; +pub const NUMERICAL_FIELD_COUNT: usize = FIELD_COUNT - 2; + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct IndicatedBar { + pub hour: u8, + pub day: u8, + pub open: f64, + pub open_pct: f64, + pub high: f64, + pub high_pct: f64, + pub low: f64, + pub low_pct: f64, + pub close: f64, + pub close_pct: f64, + pub volume: f64, + pub volume_pct: f64, + pub trades: f64, + pub trades_pct: f64, + pub close_deriv: f64, + pub close_deriv_pct: f64, + pub sma_3: f64, + pub sma_3_pct: f64, + pub sma_6: f64, + pub sma_6_pct: f64, + pub sma_12: f64, + pub sma_12_pct: f64, + pub sma_24: f64, + pub sma_24_pct: f64, + pub sma_48: f64, + pub sma_48_pct: f64, + pub sma_72: f64, + pub sma_72_pct: f64, + pub ema_3: f64, + pub ema_3_pct: f64, + pub ema_6: f64, + pub ema_6_pct: f64, + pub ema_12: f64, + pub ema_12_pct: f64, + pub ema_24: f64, + pub ema_24_pct: f64, + pub ema_48: f64, + pub ema_48_pct: f64, + pub ema_72: f64, + pub ema_72_pct: f64, + pub macd: f64, + pub macd_pct: f64, + pub macd_signal: f64, + pub macd_signal_pct: f64, + pub obv: f64, + pub obv_pct: f64, + pub rsi: f64, + pub rsi_pct: f64, + pub bbands_lower: f64, + pub bbands_lower_pct: f64, + pub bbands_mean: f64, + pub bbands_mean_pct: f64, + pub bbands_upper: f64, + pub bbands_upper_pct: f64, +} + +#[allow(clippy::too_many_lines)] +pub fn calculate_indicators(bars: &[Bar]) -> Vec { + let length = bars.len(); + + let (hour, day, open, high, low, close, volume, trades) = bars.iter().fold( + ( + Vec::with_capacity(length), + Vec::with_capacity(length), + Vec::with_capacity(length), + Vec::with_capacity(length), + Vec::with_capacity(length), + Vec::with_capacity(length), + Vec::with_capacity(length), + Vec::with_capacity(length), + ), + |(mut hour, mut day, mut open, mut high, mut low, mut close, mut volume, mut trades), + bar| { + hour.push(bar.time.hour()); + day.push(bar.time.day()); + open.push(bar.open); + high.push(bar.high); + low.push(bar.low); + close.push(bar.close); + volume.push(bar.volume); + trades.push(bar.trades as f64); + (hour, day, open, high, low, close, volume, trades) + }, + ); + + let mut close_deriv = Vec::with_capacity(length); + let mut sma_3 = Vec::with_capacity(length); + let mut sma_6 = Vec::with_capacity(length); + let mut sma_12 = Vec::with_capacity(length); + let mut sma_24 = Vec::with_capacity(length); + let mut sma_48 = Vec::with_capacity(length); + let mut sma_72 = Vec::with_capacity(length); + let mut ema_3 = Vec::with_capacity(length); + let mut ema_6 = Vec::with_capacity(length); + let mut ema_12 = Vec::with_capacity(length); + let mut ema_24 = Vec::with_capacity(length); + let mut ema_48 = Vec::with_capacity(length); + let mut ema_72 = Vec::with_capacity(length); + let mut macd = Vec::with_capacity(length); + let mut macd_signal = Vec::with_capacity(length); + let mut obv = Vec::with_capacity(length); + let mut rsi = Vec::with_capacity(length); + let mut bbands_upper = Vec::with_capacity(length); + let mut bbands_mean = Vec::with_capacity(length); + let mut bbands_lower = Vec::with_capacity(length); + + scope(|s| { + s.spawn(|_| close_deriv.extend(close.iter().deriv())); + s.spawn(|_| sma_3.extend(close.iter().sma(NonZeroUsize::new(3).unwrap()))); + s.spawn(|_| sma_6.extend(close.iter().sma(NonZeroUsize::new(6).unwrap()))); + s.spawn(|_| sma_12.extend(close.iter().sma(NonZeroUsize::new(12).unwrap()))); + s.spawn(|_| sma_24.extend(close.iter().sma(NonZeroUsize::new(24).unwrap()))); + s.spawn(|_| sma_48.extend(close.iter().sma(NonZeroUsize::new(48).unwrap()))); + s.spawn(|_| sma_72.extend(close.iter().sma(NonZeroUsize::new(72).unwrap()))); + s.spawn(|_| ema_3.extend(close.iter().ema(NonZeroUsize::new(3).unwrap()))); + s.spawn(|_| ema_6.extend(close.iter().ema(NonZeroUsize::new(6).unwrap()))); + s.spawn(|_| ema_12.extend(close.iter().ema(NonZeroUsize::new(12).unwrap()))); + s.spawn(|_| ema_24.extend(close.iter().ema(NonZeroUsize::new(24).unwrap()))); + s.spawn(|_| ema_48.extend(close.iter().ema(NonZeroUsize::new(48).unwrap()))); + s.spawn(|_| ema_72.extend(close.iter().ema(NonZeroUsize::new(72).unwrap()))); + s.spawn(|_| { + close + .iter() + .macd( + NonZeroUsize::new(12).unwrap(), + NonZeroUsize::new(26).unwrap(), + NonZeroUsize::new(9).unwrap(), + ) + .for_each(|(macd_val, signal_val)| { + macd.push(macd_val); + macd_signal.push(signal_val); + }); + }); + s.spawn(|_| { + obv.extend(bars.iter().map(|bar| (bar.close, bar.volume)).obv()); + }); + s.spawn(|_: &_| { + rsi.extend(close.iter().rsi(NonZeroUsize::new(14).unwrap())); + }); + s.spawn(|_| { + close + .iter() + .bbands(NonZeroUsize::new(20).unwrap(), 2.0) + .for_each(|(upper, mean, lower)| { + bbands_upper.push(upper); + bbands_mean.push(mean); + bbands_lower.push(lower); + }); + }) + }); + + let mut open_pct = Vec::with_capacity(length); + let mut high_pct = Vec::with_capacity(length); + let mut low_pct = Vec::with_capacity(length); + let mut close_pct = Vec::with_capacity(length); + let mut volume_pct = Vec::with_capacity(length); + let mut trades_pct = Vec::with_capacity(length); + let mut close_deriv_pct = Vec::with_capacity(length); + let mut sma_3_pct = Vec::with_capacity(length); + let mut sma_6_pct = Vec::with_capacity(length); + let mut sma_12_pct = Vec::with_capacity(length); + let mut sma_24_pct = Vec::with_capacity(length); + let mut sma_48_pct = Vec::with_capacity(length); + let mut sma_72_pct = Vec::with_capacity(length); + let mut ema_3_pct = Vec::with_capacity(length); + let mut ema_6_pct = Vec::with_capacity(length); + let mut ema_12_pct = Vec::with_capacity(length); + let mut ema_24_pct = Vec::with_capacity(length); + let mut ema_48_pct = Vec::with_capacity(length); + let mut ema_72_pct = Vec::with_capacity(length); + let mut macd_pct = Vec::with_capacity(length); + let mut macd_signal_pct = Vec::with_capacity(length); + let mut obv_pct = Vec::with_capacity(length); + let mut rsi_pct = Vec::with_capacity(length); + let mut bbands_upper_pct = Vec::with_capacity(length); + let mut bbands_mean_pct = Vec::with_capacity(length); + let mut bbands_lower_pct = Vec::with_capacity(length); + + scope(|s| { + s.spawn(|_| open_pct.extend(open.iter().pct())); + s.spawn(|_| high_pct.extend(high.iter().pct())); + s.spawn(|_| low_pct.extend(low.iter().pct())); + s.spawn(|_| close_pct.extend(close.iter().pct())); + s.spawn(|_| volume_pct.extend(volume.iter().pct())); + s.spawn(|_| trades_pct.extend(trades.iter().pct())); + s.spawn(|_| close_deriv_pct.extend(close_deriv.iter().pct())); + s.spawn(|_| sma_3_pct.extend(sma_3.iter().pct())); + s.spawn(|_| sma_6_pct.extend(sma_6.iter().pct())); + s.spawn(|_| sma_12_pct.extend(sma_12.iter().pct())); + s.spawn(|_| sma_24_pct.extend(sma_24.iter().pct())); + s.spawn(|_| sma_48_pct.extend(sma_48.iter().pct())); + s.spawn(|_| sma_72_pct.extend(sma_72.iter().pct())); + s.spawn(|_| ema_3_pct.extend(ema_3.iter().pct())); + s.spawn(|_| ema_6_pct.extend(ema_6.iter().pct())); + s.spawn(|_| ema_12_pct.extend(ema_12.iter().pct())); + s.spawn(|_| ema_24_pct.extend(ema_24.iter().pct())); + s.spawn(|_| ema_48_pct.extend(ema_48.iter().pct())); + s.spawn(|_| ema_72_pct.extend(ema_72.iter().pct())); + s.spawn(|_| macd_pct.extend(macd.iter().pct())); + s.spawn(|_| macd_signal_pct.extend(macd_signal.iter().pct())); + s.spawn(|_| obv_pct.extend(obv.iter().pct())); + s.spawn(|_| rsi_pct.extend(rsi.iter().pct())); + s.spawn(|_| bbands_upper_pct.extend(bbands_upper.iter().pct())); + s.spawn(|_| bbands_mean_pct.extend(bbands_mean.iter().pct())); + s.spawn(|_| bbands_lower_pct.extend(bbands_lower.iter().pct())); + }); + + bars.iter() + .enumerate() + .map(|(i, _)| IndicatedBar { + hour: hour[i], + day: day[i], + open: open[i], + open_pct: open_pct[i], + high: high[i], + high_pct: high_pct[i], + low: low[i], + low_pct: low_pct[i], + close: close[i], + close_pct: close_pct[i], + volume: volume[i], + volume_pct: volume_pct[i], + trades: trades[i], + trades_pct: trades_pct[i], + close_deriv: close_deriv[i], + close_deriv_pct: close_deriv_pct[i], + sma_3: sma_3[i], + sma_3_pct: sma_3_pct[i], + sma_6: sma_6[i], + sma_6_pct: sma_6_pct[i], + sma_12: sma_12[i], + sma_12_pct: sma_12_pct[i], + sma_24: sma_24[i], + sma_24_pct: sma_24_pct[i], + sma_48: sma_48[i], + sma_48_pct: sma_48_pct[i], + sma_72: sma_72[i], + sma_72_pct: sma_72_pct[i], + ema_3: ema_3[i], + ema_3_pct: ema_3_pct[i], + ema_6: ema_6[i], + ema_6_pct: ema_6_pct[i], + ema_12: ema_12[i], + ema_12_pct: ema_12_pct[i], + ema_24: ema_24[i], + ema_24_pct: ema_24_pct[i], + ema_48: ema_48[i], + ema_48_pct: ema_48_pct[i], + ema_72: ema_72[i], + ema_72_pct: ema_72_pct[i], + macd: macd[i], + macd_pct: macd_pct[i], + macd_signal: macd_signal[i], + macd_signal_pct: macd_signal_pct[i], + obv: obv[i], + obv_pct: obv_pct[i], + rsi: rsi[i], + rsi_pct: rsi_pct[i], + bbands_lower: bbands_lower[i], + bbands_lower_pct: bbands_lower_pct[i], + bbands_mean: bbands_mean[i], + bbands_mean_pct: bbands_mean_pct[i], + bbands_upper: bbands_upper[i], + bbands_upper_pct: bbands_upper_pct[i], + }) + .collect() +} + +#[cfg(test)] +mod tests { + use super::*; + use rand::{ + distributions::{Distribution, Uniform}, + Rng, + }; + use time::OffsetDateTime; + + #[test] + fn test_calculate_indicators() { + let length = 1_000_000; + + let mut rng = rand::thread_rng(); + let uniform = Uniform::new(1.0, 100.0); + let mut bars = Vec::with_capacity(length); + + for _ in 0..length { + bars.push(Bar { + symbol: "AAPL".to_string(), + time: OffsetDateTime::now_utc(), + open: uniform.sample(&mut rng), + high: uniform.sample(&mut rng), + low: uniform.sample(&mut rng), + close: uniform.sample(&mut rng), + volume: uniform.sample(&mut rng), + trades: rng.gen_range(1..100), + }); + } + + let indicated_bars = calculate_indicators(&bars); + + assert_eq!(indicated_bars.len(), length); + } +} diff --git a/src/lib/qrust/utils/de.rs b/src/lib/qrust/utils/de.rs index 728bcb8..47113e8 100644 --- a/src/lib/qrust/utils/de.rs +++ b/src/lib/qrust/utils/de.rs @@ -108,7 +108,6 @@ mod tests { use super::*; use serde::Deserialize; use serde_test::{assert_de_tokens, Token}; - use time::Time; #[test] fn test_add_slash() {