1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
//! The `run(config) -> Bundle` entry point.
//!
//! The Python mirror of the Rust run: marshal the config under the GIL, release
//! the GIL for the pure-Rust engine + writer, then re-acquire to build the
//! [`Bundle`] handle to the finalized on-disk directory
//! ([docs/06 §3](../../docs/06-python-bindings.md)).
//!
//! # One write lifecycle, shared with the core
//!
//! `run()` drives the **public Rust API only** — [`crate::run_backtest`] then
//! [`crate::write_bundle`] — the exact same code path (and the same atomic
//! writer, collision check, and `overwrite` semantics) as a Rust
//! `run_backtest` + `write_bundle`. There is no "maybe in memory" variant: the
//! bundle is written to `<output_dir>/<run_id>/` inside `run()` and the returned
//! [`Bundle`] is a handle to that finalized directory
//! ([docs/06 §6](../../docs/06-python-bindings.md)).
//!
//! # GIL discipline
//!
//! Marshalling + validation happen under the GIL (`config.to_rust()`), then
//! `py.detach` releases the GIL around the CPU-bound engine and the bundle
//! I/O, so a batch of runs can be fanned out from Python threads. The strategy
//! is an upstream `optionstratlib` type, not a Python callback, so the loop
//! never re-acquires the GIL mid-run ([docs/06 §3](../../docs/06-python-bindings.md)).
//! No panic crosses the boundary: the engine and writer return [`Result`]s,
//! mapped to a typed Python exception through [`super::errors::to_pyerr`], and
//! the whole body runs inside [`super::errors::guard_boundary`] — a
//! `catch_unwind` **outside** the `detach` region that turns any unexpected
//! panic into `ic.EngineError` with the GIL re-attached.
use PathBuf;
use *;
use Bundle;
use PyBacktestConfig;
use ;
use crateBacktestError;
use crate::;
/// Run one backtest end to end and return a [`Bundle`] handle to the finalized
/// on-disk bundle directory (`bundle.path`).
///
/// Marshals `config` under the GIL, then releases the GIL for the pure-Rust
/// engine run **and** the atomic bundle write, exactly as the Rust API does.
///
/// # Errors
///
/// Raises `ic.ConfigError` (⊂ `ValueError`) for a config / input error (no data
/// source or strategy configured, an invalid field), `ic.DataError` (⊂
/// `IOError`) for a feed / conversion / tape failure, `ic.ExecutionError` for a
/// fill failure, `ic.BundleError` (⊂ `IOError`) for a bundle-write failure, and
/// `ic.EngineError` for an arithmetic overflow or an unexpected internal panic.
/// All descend from `ic.IronCondorError`.