0.1.2 never reached PyPI: its tag was pushed before release.yml existed
on main, so no workflow fired and nothing was uploaded. PyPI's latest is
still 0.1.1.
This release therefore carries everything since 0.1.1 — parallel
grid-search optimize(), HTML reports, the O(1) data access fix, and this
week's position management — which is a minor bump, not a patch.
Adds two Broker methods for path-dependent strategies:
- close_partial(id, lot_size) scales out of a position and leaves the
remainder open under the same id, so it can keep being managed.
- update_sl(id, stop_loss) moves the stop in place. A trailing stop no
longer has to close and reopen, which paid spread and commission on
every step.
Both are reachable from Python as Strategy.close_partial and
Strategy.update_sl.
Closing a position, part of one, or the whole book previously repeated
the same PnL and commission arithmetic in four places. That is now one
settle() helper taking the number of lots to close, so a partial close
is the same code with a smaller number and the feature made broker.rs
shorter rather than longer.
Commission splits across the legs: the entry was charged on the full
size when the position opened, so settle only takes the exit leg for
the lots being closed. Two 0.5 closes land on the same cash as one 1.0
close, which is what closing_partially_twice_matches_closing_once pins.
update_sl deliberately does not check which way the stop moves, since
widening a stop is a legitimate thing for a strategy to do.
Generated with `maturin generate-ci github`, then trimmed to run on tags
only (it rebuilt every wheel on every PR) and to a smaller target matrix.
Publishing uses PyPI trusted publishing, so no API token is stored. This
needs a one-time trusted publisher registered on PyPI for this repo and
release.yml before the publish step will succeed.
Ships parallel grid-search optimization, HTML reports, and the O(1) data
window that landed since 0.1.1.
Also tracks the sample EURUSD hourly CSV. The examples and the README's
157x benchmark all read data/EURUSD_1H.csv, which was gitignored, so none
of them ran on a fresh clone. `data/` becomes `data/*` plus a negation
because git cannot re-include a file whose parent directory is excluded.
Replace four map_or(false, ..) calls in check_sl_tp with is_some_and, which
reads closer to the intent ("there is a stop and price hit it").
CI now runs `cargo clippy --all-targets -- -D warnings` in place of
`cargo check` — clippy is a superset, so this is more coverage in one
fewer step, and -D warnings stops the lint debt building back up.
Covers buy/sell close PnL, commission charged on open and close,
long SL fills at the stop price (not bar.close), positions staying
open when neither SL nor TP is hit, and unrealized equity.
python/backtest.py and python/simple_strategy.py were leftover
duplicates from before the PyO3 restructure; nothing referenced them.
__pycache__ was never gitignored.
- Trade.pnl now stores net pnl (after exit commission) so per-trade stats are accurate
- Position pyclass uses from_py_object to fix deprecation warning
- Removed dead AttributeError swallow in engine.rs
- Strategy gains self.data, self.index, self.cash, self.equity properties
- Broker.cash exposed to Python via pyo3(get)
- Sharpe ratio added to Stats (unannualized)
- Added examples/sma_cross.py and examples/compare_bt.py
- Logic verified against backtesting.py: 34 trades, 29.4% win rate match
- Replaced manual CSV parsing with csv crate, columns now looked up by name
- Fixed Rust example path and contract_size
- Added CHANGELOG.md for release tracking
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>