diff --git a/Cargo.lock b/Cargo.lock index dd04e397..095d236c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1974,7 +1974,6 @@ dependencies = [ "approx", "criterion", "proptest", - "serde_json", "wickra-core", "wickra-data", ] @@ -2003,10 +2002,19 @@ dependencies = [ "tokio", "tokio-tungstenite", "url", - "wickra", "wickra-core", ] +[[package]] +name = "wickra-examples" +version = "0.0.0" +dependencies = [ + "serde_json", + "tokio", + "wickra", + "wickra-data", +] + [[package]] name = "wickra-node" version = "0.1.4" diff --git a/Cargo.toml b/Cargo.toml index 695e4971..b1578d72 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ members = [ "bindings/python", "bindings/wasm", "bindings/node", + "examples/rust", ] exclude = ["fuzz"] diff --git a/README.md b/README.md index ce79e2ff..41861645 100644 --- a/README.md +++ b/README.md @@ -120,7 +120,7 @@ inherit it automatically. | Python (PyO3) | `pip install wickra` | `examples/python/backtest.py` | | Node.js (napi-rs) | `npm install wickra` | `bindings/node/examples/backtest.js` | | Browser / WASM | `npm install wickra-wasm` | `bindings/wasm/examples/index.html` | -| Rust | `cargo add wickra` | `crates/wickra/examples/backtest.rs` | +| Rust | `cargo add wickra` | `examples/rust/src/bin/backtest.rs` | Each binding ships several runnable examples (streaming, backtest, live feed); [`examples/README.md`](examples/README.md) is the full cross-language index. @@ -182,23 +182,22 @@ A Python live-trading example using the public `websockets` package lives at wickra/ ├── crates/ │ ├── wickra-core/ core engine + all 71 indicators -│ ├── wickra/ top-level facade crate (publishes on crates.io) -│ │ + benches/, examples/ (backtest, fetch_btcusdt) -│ │ and examples/data/ real BTCUSDT datasets +│ ├── wickra/ top-level facade crate (publishes on crates.io) + benches/ │ └── wickra-data/ CSV reader, tick aggregator, live exchange feeds -│ + examples/live_binance.rs ├── bindings/ │ ├── python/ PyO3 + maturin (publishes on PyPI) │ ├── node/ napi-rs (publishes on npm) + examples/ │ └── wasm/ wasm-bindgen (browsers, bundlers, Node) + examples/ ├── examples/ examples/README.md indexes every language +│ ├── data/ real BTCUSDT OHLCV datasets, one per timeframe +│ ├── rust/ Rust workspace member (`wickra-examples`) │ └── python/ backtest, live trading, parallel assets, multi-tf └── .github/workflows/ CI and release pipelines ``` -Rust benchmarks and examples live inside their crate -(`crates/wickra/benches/`, `crates//examples/`); there is no -top-level `benches/` directory. +Rust benchmarks live in `crates/wickra/benches/`; runnable Rust examples live +in the workspace member crate at `examples/rust/`. There is no top-level +`benches/` directory. ## Building everything from source diff --git a/crates/wickra-data/Cargo.toml b/crates/wickra-data/Cargo.toml index 8a28072e..355fe244 100644 --- a/crates/wickra-data/Cargo.toml +++ b/crates/wickra-data/Cargo.toml @@ -42,9 +42,3 @@ live-binance = ["dep:tokio", "dep:tokio-tungstenite", "dep:futures-util", "dep:u [dev-dependencies] approx = { workspace = true } tempfile = "3" -wickra = { path = "../wickra" } -tokio = { version = "1", features = ["macros", "rt-multi-thread"] } - -[[example]] -name = "live_binance" -required-features = ["live-binance"] diff --git a/crates/wickra/Cargo.toml b/crates/wickra/Cargo.toml index 993a6601..bc6b4465 100644 --- a/crates/wickra/Cargo.toml +++ b/crates/wickra/Cargo.toml @@ -32,9 +32,6 @@ approx = { workspace = true } criterion = { workspace = true } proptest = { workspace = true } wickra-data = { path = "../wickra-data" } -# Only the `fetch_btcusdt` example parses Binance REST JSON; a dev-dependency -# never reaches a downstream consumer's dependency tree. -serde_json = "1" [[bench]] name = "indicators" diff --git a/docs/wiki/Data-Layer.md b/docs/wiki/Data-Layer.md index 9bf7833f..f84bc754 100644 --- a/docs/wiki/Data-Layer.md +++ b/docs/wiki/Data-Layer.md @@ -150,10 +150,10 @@ dropped connection, skips non-kline frames (subscription acks, heartbeats), applies a read timeout and message-size limits, and tracks a closed flag so a deliberately closed stream is not reused. -A runnable example lives at `crates/wickra-data/examples/live_binance.rs`: +A runnable example lives at `examples/rust/src/bin/live_binance.rs`: ```bash -cargo run -p wickra-data --example live_binance --features live-binance +cargo run -p wickra-examples --bin live_binance ``` ## Example datasets @@ -183,7 +183,7 @@ Binance REST API and needs the system `curl` (shipped with Windows 10+, macOS and Linux): ```bash -cargo run -p wickra --example fetch_btcusdt +cargo run -p wickra-examples --bin fetch_btcusdt ``` ## See also diff --git a/docs/wiki/Quickstart-Rust.md b/docs/wiki/Quickstart-Rust.md index 883f0c05..cb1779ff 100644 --- a/docs/wiki/Quickstart-Rust.md +++ b/docs/wiki/Quickstart-Rust.md @@ -119,17 +119,17 @@ exact contract. ## A deeper example -`crates/wickra/examples/backtest.rs` shipped with the workspace computes a -panel of indicators (RSI, EMA, Bollinger, MACD, ATR, ADX, OBV) over an OHLCV -CSV by way of `wickra-data`: +`examples/rust/src/bin/backtest.rs` (in the `wickra-examples` workspace +crate) computes a panel of indicators (RSI, EMA, Bollinger, MACD, ATR, ADX, +OBV) over an OHLCV CSV by way of `wickra-data`: ```bash -cargo run --release --example backtest -- path/to/ohlcv.csv +cargo run --release -p wickra-examples --bin backtest -- path/to/ohlcv.csv ``` For live-data work, `wickra-data` ships a streaming CSV reader, a tick-to-candle aggregator, a candle resampler, and a Binance kline WebSocket -adapter under the `live-binance` feature. `crates/wickra-data/examples/live_binance.rs` +adapter under the `live-binance` feature. `examples/rust/src/bin/live_binance.rs` is the canonical example for the latter. ## See also diff --git a/examples/README.md b/examples/README.md index aac43387..df354285 100644 --- a/examples/README.md +++ b/examples/README.md @@ -5,13 +5,15 @@ to the code they exercise so the language tooling (`cargo run --example`, `node`) can find them; the Python examples have no crate of their own and live here under [`python/`](python/). -## Rust — `crates/*/examples/` +## Rust — `examples/rust/` + +The Rust examples live in the `wickra-examples` workspace member crate. | Example | What it does | Run | | --- | --- | --- | -| `backtest.rs` | Compute a basket of indicators over an OHLCV CSV and print a summary. | `cargo run -p wickra --example backtest -- ` | -| `fetch_btcusdt.rs` | Download real BTCUSDT klines from the Binance REST API into `examples/data/`. | `cargo run -p wickra --example fetch_btcusdt` | -| `live_binance.rs` | Stream live Binance klines through an indicator over a resilient WebSocket. | `cargo run -p wickra-data --example live_binance --features live-binance` | +| `backtest.rs` | Compute a basket of indicators over an OHLCV CSV and print a summary. | `cargo run -p wickra-examples --bin backtest -- ` | +| `fetch_btcusdt.rs` | Download real BTCUSDT klines from the Binance REST API into `examples/data/`. | `cargo run -p wickra-examples --bin fetch_btcusdt` | +| `live_binance.rs` | Stream live Binance klines through an indicator over a resilient WebSocket. | `cargo run -p wickra-examples --bin live_binance` | ## Python — `examples/python/` @@ -46,4 +48,4 @@ Build the native module first: `cd bindings/node && npm install && npx napi buil per timeframe (1m, 5m, 15m, 1h, 12h, 1d, 1month), in the standard `timestamp,open,high,low,close,volume` layout. The Rust and Node backtest examples and the indicator benchmarks run against them. Regenerate them with -the latest market history via `cargo run -p wickra --example fetch_btcusdt`. +the latest market history via `cargo run -p wickra-examples --bin fetch_btcusdt`. diff --git a/examples/rust/Cargo.toml b/examples/rust/Cargo.toml new file mode 100644 index 00000000..f1f2b626 --- /dev/null +++ b/examples/rust/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "wickra-examples" +version = "0.0.0" +publish = false +description = "Runnable Rust examples for the Wickra technical-analysis library." +authors.workspace = true +edition.workspace = true +rust-version.workspace = true +license.workspace = true +repository.workspace = true +homepage.workspace = true +readme = "README.md" + +[lints] +workspace = true + +[dependencies] +# All examples sit on top of the indicator engine. +wickra = { path = "../../crates/wickra" } +# The data layer is needed by every example except streaming/parallel: CSV +# reading, the Binance live feed and the resampler all live here. The +# `live-binance` feature is always on for this crate so the live_binance +# binary just compiles. +wickra-data = { path = "../../crates/wickra-data", features = ["live-binance"] } +# fetch_btcusdt parses the Binance REST kline response. +serde_json = "1" +# live_binance uses #[tokio::main]; the current-thread runtime is enough. +tokio = { version = "1", features = ["rt", "macros"] } diff --git a/crates/wickra/examples/backtest.rs b/examples/rust/src/bin/backtest.rs similarity index 97% rename from crates/wickra/examples/backtest.rs rename to examples/rust/src/bin/backtest.rs index 798e5619..ca1af974 100644 --- a/crates/wickra/examples/backtest.rs +++ b/examples/rust/src/bin/backtest.rs @@ -2,7 +2,7 @@ //! //! Build with: //! ```text -//! cargo run --release --example backtest -- path/to/ohlcv.csv +//! cargo run --release -p wickra-examples --bin backtest -- path/to/ohlcv.csv //! ``` use std::env; diff --git a/crates/wickra/examples/fetch_btcusdt.rs b/examples/rust/src/bin/fetch_btcusdt.rs similarity index 95% rename from crates/wickra/examples/fetch_btcusdt.rs rename to examples/rust/src/bin/fetch_btcusdt.rs index c6224f2d..0bfe150e 100644 --- a/crates/wickra/examples/fetch_btcusdt.rs +++ b/examples/rust/src/bin/fetch_btcusdt.rs @@ -1,13 +1,13 @@ //! Rust example: download real BTCUSDT spot candles from the Binance REST API //! and write them as CSV datasets under `examples/data/`. //! -//! These are the datasets the indicator benchmarks (`benches/indicators.rs`) -//! and the `example_data` integration test run against. They live at the -//! workspace `examples/data/` directory. Re-run this example to refresh -//! them with the latest market history: +//! These are the datasets the indicator benchmarks (`crates/wickra/benches/ +//! indicators.rs`) and the `example_data` integration test run against. They +//! live at the workspace `examples/data/` directory. Re-run this example to +//! refresh them with the latest market history: //! //! ```text -//! cargo run -p wickra --example fetch_btcusdt +//! cargo run -p wickra-examples --bin fetch_btcusdt //! ``` //! //! HTTPS is handled by shelling out to the system `curl` — shipped with @@ -98,8 +98,6 @@ fn main() -> Result<(), Box> { let data_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")) .join("..") - .join("..") - .join("examples") .join("data"); std::fs::create_dir_all(&data_dir)?; diff --git a/crates/wickra-data/examples/live_binance.rs b/examples/rust/src/bin/live_binance.rs similarity index 92% rename from crates/wickra-data/examples/live_binance.rs rename to examples/rust/src/bin/live_binance.rs index 47f7381d..b864525c 100644 --- a/crates/wickra-data/examples/live_binance.rs +++ b/examples/rust/src/bin/live_binance.rs @@ -2,7 +2,7 @@ //! //! Build with: //! ```text -//! cargo run --release --example live_binance --features wickra-data/live-binance -- BTCUSDT +//! cargo run --release -p wickra-examples --bin live_binance -- BTCUSDT //! ``` //! //! The example prints a line per bar close. Hit Ctrl+C to stop.