quantex 0.3.4__tar.gz → 0.4.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {quantex-0.3.4 → quantex-0.4.1}/PKG-INFO +79 -21
- {quantex-0.3.4 → quantex-0.4.1}/README.md +78 -20
- {quantex-0.3.4 → quantex-0.4.1}/pyproject.toml +1 -1
- {quantex-0.3.4 → quantex-0.4.1}/src/quantex/__init__.py +1 -1
- quantex-0.4.1/src/quantex/backtester/__init__.py +45 -0
- {quantex-0.3.4/src/quantex → quantex-0.4.1/src/quantex/backtester}/backtester.py +145 -568
- quantex-0.4.1/src/quantex/backtester/constants.py +10 -0
- quantex-0.4.1/src/quantex/backtester/data_splits.py +100 -0
- quantex-0.4.1/src/quantex/backtester/metrics.py +127 -0
- quantex-0.4.1/src/quantex/backtester/montecarlo.py +459 -0
- quantex-0.4.1/src/quantex/backtester/parallel.py +142 -0
- quantex-0.4.1/src/quantex/backtester/reports.py +219 -0
- quantex-0.4.1/src/quantex/broker/__init__.py +11 -0
- {quantex-0.3.4/src/quantex → quantex-0.4.1/src/quantex/broker}/broker.py +2 -76
- quantex-0.4.1/src/quantex/broker/types.py +93 -0
- quantex-0.3.4/src/quantex/enums.py +0 -18
- {quantex-0.3.4 → quantex-0.4.1}/LICENSE.md +0 -0
- {quantex-0.3.4 → quantex-0.4.1}/src/quantex/datasource.py +0 -0
- {quantex-0.3.4 → quantex-0.4.1}/src/quantex/helpers.py +0 -0
- {quantex-0.3.4 → quantex-0.4.1}/src/quantex/indicators.py +0 -0
- {quantex-0.3.4 → quantex-0.4.1}/src/quantex/strategy.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: quantex
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.1
|
|
4
4
|
Summary: A simple quant strategy creation and backtesting package.
|
|
5
5
|
License: MIT
|
|
6
6
|
Author: Daniel Green
|
|
@@ -26,9 +26,9 @@ It gives you a small set of building blocks:
|
|
|
26
26
|
|
|
27
27
|
- [`Strategy`](src/quantex/strategy.py:9) for your trading rules
|
|
28
28
|
- [`DataSource`](src/quantex/datasource.py:6) plus [`CSVDataSource`](src/quantex/datasource.py:194) and [`ParquetDataSource`](src/quantex/datasource.py:228) for OHLCV market data
|
|
29
|
-
- [`Broker`](src/quantex/broker.py:113) objects, created automatically per symbol, for order placement and position state
|
|
30
|
-
- [`SimpleBacktester`](src/quantex/backtester.py:
|
|
31
|
-
- [`BacktestReport`](src/quantex/backtester.py:
|
|
29
|
+
- [`Broker`](src/quantex/broker/broker.py:113) objects, created automatically per symbol, for order placement and position state
|
|
30
|
+
- [`SimpleBacktester`](src/quantex/backtester/backtester.py:26) for simulation and parameter search
|
|
31
|
+
- [`BacktestReport`](src/quantex/backtester/reports.py:4) for results, equity history, and summary statistics
|
|
32
32
|
|
|
33
33
|
The project is intentionally small. It does not try to be a full research platform, portfolio database, or live-trading engine. Instead, it focuses on a straightforward workflow: load historical bars, define strategy logic, simulate orders, and inspect the results.
|
|
34
34
|
|
|
@@ -48,8 +48,8 @@ At runtime, a typical Quantex workflow looks like this:
|
|
|
48
48
|
2. In [`Strategy.init()`](src/quantex/strategy.py:52), attach one or more data sources with [`Strategy.add_data()`](src/quantex/strategy.py:98).
|
|
49
49
|
3. Still in [`Strategy.init()`](src/quantex/strategy.py:52), build indicator arrays with the built-in indicator catalog on `self.ta` or the package-level [`indicators`](src/quantex/indicators.py), then register them with [`Strategy.Indicator()`](src/quantex/strategy.py:126).
|
|
50
50
|
4. In [`Strategy.next()`](src/quantex/strategy.py:71), read the current bar through properties such as [`DataSource.COpen`](src/quantex/datasource.py:145) and [`DataSource.CClose`](src/quantex/datasource.py:175), then place orders through the broker stored in [`Strategy.positions`](src/quantex/strategy.py:47).
|
|
51
|
-
5. Run the strategy with [`SimpleBacktester.run()`](src/quantex/backtester.py:414).
|
|
52
|
-
6. Inspect the returned [`BacktestReport`](src/quantex/backtester.py:
|
|
51
|
+
5. Run the strategy with [`SimpleBacktester.run()`](src/quantex/backtester/backtester.py:414).
|
|
52
|
+
6. Inspect the returned [`BacktestReport`](src/quantex/backtester/reports.py:4), including [`BacktestReport.total_return`](src/quantex/backtester/reports.py:68), [`BacktestReport.periods_per_year`](src/quantex/backtester/reports.py:58), [`BacktestReport.plot()`](src/quantex/backtester/reports.py:87), and the printable summary from [`BacktestReport.__str__()`](src/quantex/backtester/reports.py:101).
|
|
53
53
|
|
|
54
54
|
## Usage
|
|
55
55
|
|
|
@@ -125,22 +125,22 @@ report.plot()
|
|
|
125
125
|
|
|
126
126
|
### 4. Understand what happens during the backtest
|
|
127
127
|
|
|
128
|
-
When you call [`SimpleBacktester.run()`](src/quantex/backtester.py:414):
|
|
128
|
+
When you call [`SimpleBacktester.run()`](src/quantex/backtester/backtester.py:414):
|
|
129
129
|
|
|
130
|
-
- the backtester deep-copies your strategy in [`SimpleBacktester.__init__()`](src/quantex/backtester.py:
|
|
131
|
-
- starting cash is split evenly across all attached symbols in [`SimpleBacktester.run()`](src/quantex/backtester.py:439)
|
|
130
|
+
- the backtester deep-copies your strategy in [`SimpleBacktester.__init__()`](src/quantex/backtester/backtester.py:26)
|
|
131
|
+
- starting cash is split evenly across all attached symbols in [`SimpleBacktester.run()`](src/quantex/backtester/backtester.py:439)
|
|
132
132
|
- each data source advances one bar at a time by updating [`DataSource.current_index`](src/quantex/datasource.py:62)
|
|
133
|
-
- each symbol's broker processes pending orders through [`Broker._iterate()`](src/quantex/broker.py:483)
|
|
133
|
+
- each symbol's broker processes pending orders through [`Broker._iterate()`](src/quantex/broker/broker.py:483)
|
|
134
134
|
- market orders execute at the current bar's open price through [`DataSource.COpen`](src/quantex/datasource.py:145)
|
|
135
|
-
- equity is tracked into the final [`BacktestReport.PnlRecord`](src/quantex/backtester.py:
|
|
135
|
+
- equity is tracked into the final [`BacktestReport.PnlRecord`](src/quantex/backtester/reports.py:52)
|
|
136
136
|
|
|
137
137
|
### 5. Understand order sizing
|
|
138
138
|
|
|
139
139
|
Order sizing in Quantex is simple but important:
|
|
140
140
|
|
|
141
|
-
- [`Broker.buy()`](src/quantex/broker.py:159) treats `quantity` as a fraction of available cash unless you pass `amount`
|
|
142
|
-
- [`Broker.sell()`](src/quantex/broker.py:235) uses the same sizing calculation and can open or increase a short position
|
|
143
|
-
- [`Broker.close()`](src/quantex/broker.py:307) places a market order that offsets the current position
|
|
141
|
+
- [`Broker.buy()`](src/quantex/broker/broker.py:159) treats `quantity` as a fraction of available cash unless you pass `amount`
|
|
142
|
+
- [`Broker.sell()`](src/quantex/broker/broker.py:235) uses the same sizing calculation and can open or increase a short position
|
|
143
|
+
- [`Broker.close()`](src/quantex/broker/broker.py:307) places a market order that offsets the current position
|
|
144
144
|
|
|
145
145
|
Because of this design, `buy(0.5)` means “use roughly half of the broker cash for this symbol”, not “buy half a share”.
|
|
146
146
|
|
|
@@ -194,20 +194,20 @@ class MacdTrendStrategy(Strategy):
|
|
|
194
194
|
|
|
195
195
|
### Broker and orders
|
|
196
196
|
|
|
197
|
-
Each call to [`Strategy.add_data()`](src/quantex/strategy.py:98) also creates a [`Broker`](src/quantex/broker.py:113) for that symbol.
|
|
197
|
+
Each call to [`Strategy.add_data()`](src/quantex/strategy.py:98) also creates a [`Broker`](src/quantex/broker/broker.py:113) for that symbol.
|
|
198
198
|
|
|
199
199
|
Supported order behavior in the current codebase:
|
|
200
200
|
|
|
201
|
-
- market orders and limit orders via [`OrderType`](src/quantex/broker.py:
|
|
202
|
-
- pending, active, and complete order states via [`OrderStatus`](src/quantex/broker.py:
|
|
203
|
-
- optional stop-loss and take-profit triggers stored on [`Order`](src/quantex/broker.py:52)
|
|
204
|
-
- percentage or cash commissions via [`CommissionType`](src/quantex/
|
|
201
|
+
- market orders and limit orders via [`OrderType`](src/quantex/broker/types.py:4)
|
|
202
|
+
- pending, active, and complete order states via [`OrderStatus`](src/quantex/broker/types.py:16)
|
|
203
|
+
- optional stop-loss and take-profit triggers stored on [`Order`](src/quantex/broker/broker.py:52)
|
|
204
|
+
- percentage or cash commissions via [`CommissionType`](src/quantex/broker/types.py:28)
|
|
205
205
|
|
|
206
206
|
## Optimization
|
|
207
207
|
|
|
208
|
-
[`SimpleBacktester.optimize()`](src/quantex/backtester.py:485) runs a grid search over every parameter combination you provide.
|
|
208
|
+
[`SimpleBacktester.optimize()`](src/quantex/backtester/backtester.py:485) runs a grid search over every parameter combination you provide.
|
|
209
209
|
|
|
210
|
-
[`SimpleBacktester.optimize_parallel()`](src/quantex/backtester.py:659) does the same work in multiple processes, then re-runs the best parameter set locally to produce a full [`BacktestReport`](src/quantex/backtester.py:
|
|
210
|
+
[`SimpleBacktester.optimize_parallel()`](src/quantex/backtester/backtester.py:659) does the same work in multiple processes, then re-runs the best parameter set locally to produce a full [`BacktestReport`](src/quantex/backtester/reports.py:4).
|
|
211
211
|
|
|
212
212
|
Minimal example:
|
|
213
213
|
|
|
@@ -227,6 +227,64 @@ print(best_report)
|
|
|
227
227
|
print(results.head())
|
|
228
228
|
```
|
|
229
229
|
|
|
230
|
+
### Train/Validate/Test Optimization
|
|
231
|
+
|
|
232
|
+
[`SimpleBacktester.optimize_with_split()`](src/quantex/backtester/backtester.py:564) performs grid search with ML-style train/validate/test data splits to help detect overfitting.
|
|
233
|
+
|
|
234
|
+
```python
|
|
235
|
+
result = backtester.optimize_with_split(
|
|
236
|
+
{"fast_period": [5, 10, 15], "slow_period": [20, 30, 50]},
|
|
237
|
+
train_ratio=0.6,
|
|
238
|
+
validate_ratio=0.2,
|
|
239
|
+
test_ratio=0.2,
|
|
240
|
+
selection_criterion="validate", # Select best params based on validate performance
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
print(f"Best params: {result.best_params}")
|
|
244
|
+
print(f"Train Sharpe: {result.train_metrics['sharpe']}")
|
|
245
|
+
print(f"Validate Sharpe: {result.validate_metrics['sharpe']}")
|
|
246
|
+
print(f"Test Sharpe: {result.test_metrics['sharpe']}")
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### Gradient Descent Optimization
|
|
250
|
+
|
|
251
|
+
[`SimpleBacktester.optimize_gradient_descent()`](src/quantex/backtester/backtester.py:852) uses gradient descent for continuous parameter optimization, supporting momentum, learning rate schedules, and integer parameter handling.
|
|
252
|
+
|
|
253
|
+
```python
|
|
254
|
+
result = backtester.optimize_gradient_descent(
|
|
255
|
+
param_init={"fast_period": 10.0, "slow_period": 30.0},
|
|
256
|
+
param_bounds={
|
|
257
|
+
"fast_period": (2.0, 50.0),
|
|
258
|
+
"slow_period": (10.0, 100.0)
|
|
259
|
+
},
|
|
260
|
+
learning_rate=0.01,
|
|
261
|
+
iterations=100,
|
|
262
|
+
momentum=0.9,
|
|
263
|
+
integer_params={"fast_period", "slow_period"},
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
print(f"Optimized params: {result.best_params}")
|
|
267
|
+
print(result.train_report)
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### Monte Carlo Simulation
|
|
271
|
+
|
|
272
|
+
[`SimpleBacktester.monte_carlo()`](src/quantex/backtester/backtester.py:1183) runs Monte Carlo simulations to test strategy robustness through two modes:
|
|
273
|
+
|
|
274
|
+
- **Trade Order Randomization** ([`MonteCarloMode.TRADE_ORDER`](src/quantex/backtester/montecarlo.py:25)): Shuffles the sequence of trade execution while keeping the same trades
|
|
275
|
+
- **Price Path Resampling** ([`MonteCarloMode.PRICE_PATH`](src/quantex/backtester/montecarlo.py:27)): Creates synthetic market scenarios from historical returns
|
|
276
|
+
|
|
277
|
+
```python
|
|
278
|
+
result = backtester.monte_carlo(
|
|
279
|
+
simulations=500,
|
|
280
|
+
mode="both", # Run both trade order and price path simulations
|
|
281
|
+
seed=42,
|
|
282
|
+
)
|
|
283
|
+
|
|
284
|
+
print(result) # Print summary statistics (percentiles, confidence intervals)
|
|
285
|
+
result.plot() # Show spaghetti plot of equity curves
|
|
286
|
+
```
|
|
287
|
+
|
|
230
288
|
## Documentation
|
|
231
289
|
|
|
232
290
|
Project documentation is built with MkDocs. The main docs entry point is [`docs/index.md`](docs/index.md), and usage guides live under [`docs/usage/`](docs/usage/).
|
|
@@ -6,9 +6,9 @@ It gives you a small set of building blocks:
|
|
|
6
6
|
|
|
7
7
|
- [`Strategy`](src/quantex/strategy.py:9) for your trading rules
|
|
8
8
|
- [`DataSource`](src/quantex/datasource.py:6) plus [`CSVDataSource`](src/quantex/datasource.py:194) and [`ParquetDataSource`](src/quantex/datasource.py:228) for OHLCV market data
|
|
9
|
-
- [`Broker`](src/quantex/broker.py:113) objects, created automatically per symbol, for order placement and position state
|
|
10
|
-
- [`SimpleBacktester`](src/quantex/backtester.py:
|
|
11
|
-
- [`BacktestReport`](src/quantex/backtester.py:
|
|
9
|
+
- [`Broker`](src/quantex/broker/broker.py:113) objects, created automatically per symbol, for order placement and position state
|
|
10
|
+
- [`SimpleBacktester`](src/quantex/backtester/backtester.py:26) for simulation and parameter search
|
|
11
|
+
- [`BacktestReport`](src/quantex/backtester/reports.py:4) for results, equity history, and summary statistics
|
|
12
12
|
|
|
13
13
|
The project is intentionally small. It does not try to be a full research platform, portfolio database, or live-trading engine. Instead, it focuses on a straightforward workflow: load historical bars, define strategy logic, simulate orders, and inspect the results.
|
|
14
14
|
|
|
@@ -28,8 +28,8 @@ At runtime, a typical Quantex workflow looks like this:
|
|
|
28
28
|
2. In [`Strategy.init()`](src/quantex/strategy.py:52), attach one or more data sources with [`Strategy.add_data()`](src/quantex/strategy.py:98).
|
|
29
29
|
3. Still in [`Strategy.init()`](src/quantex/strategy.py:52), build indicator arrays with the built-in indicator catalog on `self.ta` or the package-level [`indicators`](src/quantex/indicators.py), then register them with [`Strategy.Indicator()`](src/quantex/strategy.py:126).
|
|
30
30
|
4. In [`Strategy.next()`](src/quantex/strategy.py:71), read the current bar through properties such as [`DataSource.COpen`](src/quantex/datasource.py:145) and [`DataSource.CClose`](src/quantex/datasource.py:175), then place orders through the broker stored in [`Strategy.positions`](src/quantex/strategy.py:47).
|
|
31
|
-
5. Run the strategy with [`SimpleBacktester.run()`](src/quantex/backtester.py:414).
|
|
32
|
-
6. Inspect the returned [`BacktestReport`](src/quantex/backtester.py:
|
|
31
|
+
5. Run the strategy with [`SimpleBacktester.run()`](src/quantex/backtester/backtester.py:414).
|
|
32
|
+
6. Inspect the returned [`BacktestReport`](src/quantex/backtester/reports.py:4), including [`BacktestReport.total_return`](src/quantex/backtester/reports.py:68), [`BacktestReport.periods_per_year`](src/quantex/backtester/reports.py:58), [`BacktestReport.plot()`](src/quantex/backtester/reports.py:87), and the printable summary from [`BacktestReport.__str__()`](src/quantex/backtester/reports.py:101).
|
|
33
33
|
|
|
34
34
|
## Usage
|
|
35
35
|
|
|
@@ -105,22 +105,22 @@ report.plot()
|
|
|
105
105
|
|
|
106
106
|
### 4. Understand what happens during the backtest
|
|
107
107
|
|
|
108
|
-
When you call [`SimpleBacktester.run()`](src/quantex/backtester.py:414):
|
|
108
|
+
When you call [`SimpleBacktester.run()`](src/quantex/backtester/backtester.py:414):
|
|
109
109
|
|
|
110
|
-
- the backtester deep-copies your strategy in [`SimpleBacktester.__init__()`](src/quantex/backtester.py:
|
|
111
|
-
- starting cash is split evenly across all attached symbols in [`SimpleBacktester.run()`](src/quantex/backtester.py:439)
|
|
110
|
+
- the backtester deep-copies your strategy in [`SimpleBacktester.__init__()`](src/quantex/backtester/backtester.py:26)
|
|
111
|
+
- starting cash is split evenly across all attached symbols in [`SimpleBacktester.run()`](src/quantex/backtester/backtester.py:439)
|
|
112
112
|
- each data source advances one bar at a time by updating [`DataSource.current_index`](src/quantex/datasource.py:62)
|
|
113
|
-
- each symbol's broker processes pending orders through [`Broker._iterate()`](src/quantex/broker.py:483)
|
|
113
|
+
- each symbol's broker processes pending orders through [`Broker._iterate()`](src/quantex/broker/broker.py:483)
|
|
114
114
|
- market orders execute at the current bar's open price through [`DataSource.COpen`](src/quantex/datasource.py:145)
|
|
115
|
-
- equity is tracked into the final [`BacktestReport.PnlRecord`](src/quantex/backtester.py:
|
|
115
|
+
- equity is tracked into the final [`BacktestReport.PnlRecord`](src/quantex/backtester/reports.py:52)
|
|
116
116
|
|
|
117
117
|
### 5. Understand order sizing
|
|
118
118
|
|
|
119
119
|
Order sizing in Quantex is simple but important:
|
|
120
120
|
|
|
121
|
-
- [`Broker.buy()`](src/quantex/broker.py:159) treats `quantity` as a fraction of available cash unless you pass `amount`
|
|
122
|
-
- [`Broker.sell()`](src/quantex/broker.py:235) uses the same sizing calculation and can open or increase a short position
|
|
123
|
-
- [`Broker.close()`](src/quantex/broker.py:307) places a market order that offsets the current position
|
|
121
|
+
- [`Broker.buy()`](src/quantex/broker/broker.py:159) treats `quantity` as a fraction of available cash unless you pass `amount`
|
|
122
|
+
- [`Broker.sell()`](src/quantex/broker/broker.py:235) uses the same sizing calculation and can open or increase a short position
|
|
123
|
+
- [`Broker.close()`](src/quantex/broker/broker.py:307) places a market order that offsets the current position
|
|
124
124
|
|
|
125
125
|
Because of this design, `buy(0.5)` means “use roughly half of the broker cash for this symbol”, not “buy half a share”.
|
|
126
126
|
|
|
@@ -174,20 +174,20 @@ class MacdTrendStrategy(Strategy):
|
|
|
174
174
|
|
|
175
175
|
### Broker and orders
|
|
176
176
|
|
|
177
|
-
Each call to [`Strategy.add_data()`](src/quantex/strategy.py:98) also creates a [`Broker`](src/quantex/broker.py:113) for that symbol.
|
|
177
|
+
Each call to [`Strategy.add_data()`](src/quantex/strategy.py:98) also creates a [`Broker`](src/quantex/broker/broker.py:113) for that symbol.
|
|
178
178
|
|
|
179
179
|
Supported order behavior in the current codebase:
|
|
180
180
|
|
|
181
|
-
- market orders and limit orders via [`OrderType`](src/quantex/broker.py:
|
|
182
|
-
- pending, active, and complete order states via [`OrderStatus`](src/quantex/broker.py:
|
|
183
|
-
- optional stop-loss and take-profit triggers stored on [`Order`](src/quantex/broker.py:52)
|
|
184
|
-
- percentage or cash commissions via [`CommissionType`](src/quantex/
|
|
181
|
+
- market orders and limit orders via [`OrderType`](src/quantex/broker/types.py:4)
|
|
182
|
+
- pending, active, and complete order states via [`OrderStatus`](src/quantex/broker/types.py:16)
|
|
183
|
+
- optional stop-loss and take-profit triggers stored on [`Order`](src/quantex/broker/broker.py:52)
|
|
184
|
+
- percentage or cash commissions via [`CommissionType`](src/quantex/broker/types.py:28)
|
|
185
185
|
|
|
186
186
|
## Optimization
|
|
187
187
|
|
|
188
|
-
[`SimpleBacktester.optimize()`](src/quantex/backtester.py:485) runs a grid search over every parameter combination you provide.
|
|
188
|
+
[`SimpleBacktester.optimize()`](src/quantex/backtester/backtester.py:485) runs a grid search over every parameter combination you provide.
|
|
189
189
|
|
|
190
|
-
[`SimpleBacktester.optimize_parallel()`](src/quantex/backtester.py:659) does the same work in multiple processes, then re-runs the best parameter set locally to produce a full [`BacktestReport`](src/quantex/backtester.py:
|
|
190
|
+
[`SimpleBacktester.optimize_parallel()`](src/quantex/backtester/backtester.py:659) does the same work in multiple processes, then re-runs the best parameter set locally to produce a full [`BacktestReport`](src/quantex/backtester/reports.py:4).
|
|
191
191
|
|
|
192
192
|
Minimal example:
|
|
193
193
|
|
|
@@ -207,6 +207,64 @@ print(best_report)
|
|
|
207
207
|
print(results.head())
|
|
208
208
|
```
|
|
209
209
|
|
|
210
|
+
### Train/Validate/Test Optimization
|
|
211
|
+
|
|
212
|
+
[`SimpleBacktester.optimize_with_split()`](src/quantex/backtester/backtester.py:564) performs grid search with ML-style train/validate/test data splits to help detect overfitting.
|
|
213
|
+
|
|
214
|
+
```python
|
|
215
|
+
result = backtester.optimize_with_split(
|
|
216
|
+
{"fast_period": [5, 10, 15], "slow_period": [20, 30, 50]},
|
|
217
|
+
train_ratio=0.6,
|
|
218
|
+
validate_ratio=0.2,
|
|
219
|
+
test_ratio=0.2,
|
|
220
|
+
selection_criterion="validate", # Select best params based on validate performance
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
print(f"Best params: {result.best_params}")
|
|
224
|
+
print(f"Train Sharpe: {result.train_metrics['sharpe']}")
|
|
225
|
+
print(f"Validate Sharpe: {result.validate_metrics['sharpe']}")
|
|
226
|
+
print(f"Test Sharpe: {result.test_metrics['sharpe']}")
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### Gradient Descent Optimization
|
|
230
|
+
|
|
231
|
+
[`SimpleBacktester.optimize_gradient_descent()`](src/quantex/backtester/backtester.py:852) uses gradient descent for continuous parameter optimization, supporting momentum, learning rate schedules, and integer parameter handling.
|
|
232
|
+
|
|
233
|
+
```python
|
|
234
|
+
result = backtester.optimize_gradient_descent(
|
|
235
|
+
param_init={"fast_period": 10.0, "slow_period": 30.0},
|
|
236
|
+
param_bounds={
|
|
237
|
+
"fast_period": (2.0, 50.0),
|
|
238
|
+
"slow_period": (10.0, 100.0)
|
|
239
|
+
},
|
|
240
|
+
learning_rate=0.01,
|
|
241
|
+
iterations=100,
|
|
242
|
+
momentum=0.9,
|
|
243
|
+
integer_params={"fast_period", "slow_period"},
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
print(f"Optimized params: {result.best_params}")
|
|
247
|
+
print(result.train_report)
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Monte Carlo Simulation
|
|
251
|
+
|
|
252
|
+
[`SimpleBacktester.monte_carlo()`](src/quantex/backtester/backtester.py:1183) runs Monte Carlo simulations to test strategy robustness through two modes:
|
|
253
|
+
|
|
254
|
+
- **Trade Order Randomization** ([`MonteCarloMode.TRADE_ORDER`](src/quantex/backtester/montecarlo.py:25)): Shuffles the sequence of trade execution while keeping the same trades
|
|
255
|
+
- **Price Path Resampling** ([`MonteCarloMode.PRICE_PATH`](src/quantex/backtester/montecarlo.py:27)): Creates synthetic market scenarios from historical returns
|
|
256
|
+
|
|
257
|
+
```python
|
|
258
|
+
result = backtester.monte_carlo(
|
|
259
|
+
simulations=500,
|
|
260
|
+
mode="both", # Run both trade order and price path simulations
|
|
261
|
+
seed=42,
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
print(result) # Print summary statistics (percentiles, confidence intervals)
|
|
265
|
+
result.plot() # Show spaghetti plot of equity curves
|
|
266
|
+
```
|
|
267
|
+
|
|
210
268
|
## Documentation
|
|
211
269
|
|
|
212
270
|
Project documentation is built with MkDocs. The main docs entry point is [`docs/index.md`](docs/index.md), and usage guides live under [`docs/usage/`](docs/usage/).
|
|
@@ -6,7 +6,7 @@ from .backtester import (
|
|
|
6
6
|
OptimizationResult as OptimizationResult,
|
|
7
7
|
TrainValidateTestSplit as TrainValidateTestSplit,
|
|
8
8
|
DataSplitMode as DataSplitMode,
|
|
9
|
+
CommissionType as CommissionType,
|
|
9
10
|
create_train_validate_test_split as create_train_validate_test_split,
|
|
10
11
|
)
|
|
11
|
-
from .enums import CommissionType as CommissionType
|
|
12
12
|
from .indicators import indicators as indicators
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Re-export all public API from submodules for backward compatibility
|
|
2
|
+
from .constants import DataSplitMode
|
|
3
|
+
from ..broker.types import CommissionType
|
|
4
|
+
from .data_splits import TrainValidateTestSplit, create_train_validate_test_split
|
|
5
|
+
from .metrics import (
|
|
6
|
+
max_drawdown,
|
|
7
|
+
_infer_periods_per_year,
|
|
8
|
+
_compute_backtest_metrics,
|
|
9
|
+
_extract_metric_value,
|
|
10
|
+
_risk_tolerance_passes,
|
|
11
|
+
)
|
|
12
|
+
from .reports import BacktestReport, OptimizationResult
|
|
13
|
+
from .backtester import SimpleBacktester
|
|
14
|
+
|
|
15
|
+
# Keep parallel exports for advanced users
|
|
16
|
+
from .parallel import _worker_init, _worker_eval
|
|
17
|
+
|
|
18
|
+
# Monte Carlo simulation
|
|
19
|
+
from .montecarlo import MonteCarloResult, MonteCarloMode
|
|
20
|
+
|
|
21
|
+
__all__ = [
|
|
22
|
+
# Constants
|
|
23
|
+
"DataSplitMode",
|
|
24
|
+
"CommissionType",
|
|
25
|
+
# Data splits
|
|
26
|
+
"TrainValidateTestSplit",
|
|
27
|
+
"create_train_validate_test_split",
|
|
28
|
+
# Metrics
|
|
29
|
+
"max_drawdown",
|
|
30
|
+
"_infer_periods_per_year",
|
|
31
|
+
"_compute_backtest_metrics",
|
|
32
|
+
"_extract_metric_value",
|
|
33
|
+
"_risk_tolerance_passes",
|
|
34
|
+
# Reports
|
|
35
|
+
"BacktestReport",
|
|
36
|
+
"OptimizationResult",
|
|
37
|
+
# Main classes
|
|
38
|
+
"SimpleBacktester",
|
|
39
|
+
# Parallel (advanced)
|
|
40
|
+
"_worker_init",
|
|
41
|
+
"_worker_eval",
|
|
42
|
+
# Monte Carlo
|
|
43
|
+
"MonteCarloResult",
|
|
44
|
+
"MonteCarloMode",
|
|
45
|
+
]
|