quantex 0.5.1__tar.gz → 0.5.2__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: quantex
3
- Version: 0.5.1
3
+ Version: 0.5.2
4
4
  Summary: A simple quant strategy creation and backtesting package.
5
5
  License: MIT
6
6
  Author: Daniel Green
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "quantex"
3
- version = "0.5.1"
3
+ version = "0.5.2"
4
4
  description = "A simple quant strategy creation and backtesting package."
5
5
  authors = [
6
6
  {name = "Daniel Green",email = "dangreen07@outlook.com"}
@@ -6,6 +6,8 @@ import numpy as np
6
6
  import pandas as pd
7
7
  from matplotlib import pyplot as plt
8
8
 
9
+ from ..broker.types import Order
10
+
9
11
 
10
12
  @dataclass
11
13
  class OptimizationResult:
@@ -58,7 +60,7 @@ class BacktestReport:
58
60
  starting_cash: np.float64
59
61
  final_cash: np.float64
60
62
  PnlRecord: pd.Series
61
- orders: list
63
+ orders: list[Order]
62
64
  tradeRecord: list[np.float64]
63
65
  margin_call_events: list[dict] | None = None
64
66
  data: pd.DataFrame = field(default_factory=lambda: pd.DataFrame())
@@ -215,59 +217,61 @@ class BacktestReport:
215
217
  if end_date is not None:
216
218
  data = data[data.index <= end_date]
217
219
 
218
- # Create marker series for buy and sell signals
220
+ # Create marker series with the same index as the data
219
221
  buy_signal = pd.Series(index=data.index, dtype=float)
220
222
  sell_signal = pd.Series(index=data.index, dtype=float)
221
223
 
222
- # Track positions to determine entries and exits
223
- # Buy orders that are not reduce_only are entries
224
- # Sell orders that are reduce_only are exits (closing long positions)
225
- # Similarly for sells: Sell orders that are not reduce_only are entries
226
- # Buy orders that are reduce_only are exits (closing short positions)
227
-
228
224
  for order in self.orders:
229
225
  timestamp = order.timestamp
230
226
 
231
- # Only plot if timestamp is in our filtered data range
227
+ # Only set signal if timestamp exists in the data index
232
228
  if timestamp not in data.index:
233
229
  continue
234
230
 
235
- price = order.price
236
- if price is None:
237
- continue
238
-
231
+ # Set the signal at the order timestamp
239
232
  if order.side == OrderSide.BUY:
240
- if not order.reduce_only:
241
- # Buy entry (opening long position)
242
- buy_signal.loc[timestamp] = price
243
- else:
244
- # Buy to close short position (exit)
245
- sell_signal.loc[timestamp] = price
233
+ buy_signal.loc[timestamp] = data.loc[timestamp, 'Close'] # type: ignore
246
234
  else: # OrderSide.SELL
247
- if not order.reduce_only:
248
- # Sell entry (opening short position)
249
- buy_signal.loc[timestamp] = price
250
- else:
251
- # Sell to close long position (exit)
252
- sell_signal.loc[timestamp] = price
235
+ sell_signal.loc[timestamp] = data.loc[timestamp, 'Close'] # type: ignore
236
+
237
+ # If no trades to plot and no data, raise an error
238
+ if data.empty:
239
+ raise ValueError("No data available to plot. Check your date range.")
253
240
 
254
- # Build addplot list with markers
255
- apds = [
256
- mpf.make_addplot(
257
- buy_signal,
258
- type="scatter",
259
- marker="^",
260
- markersize=120,
261
- color="green",
262
- ),
263
- mpf.make_addplot(
264
- sell_signal,
265
- type="scatter",
266
- marker="v",
267
- markersize=120,
268
- color="red",
269
- ),
270
- ]
241
+ # Check if there are actual trade markers (non-NaN values)
242
+ has_buy_signals = not buy_signal.dropna().empty
243
+ has_sell_signals = not sell_signal.dropna().empty
244
+
245
+ # Build addplot list with markers (only if we have data points)
246
+ apds = []
247
+ if has_buy_signals:
248
+ apds.append(
249
+ mpf.make_addplot(
250
+ buy_signal,
251
+ type="scatter",
252
+ marker="^",
253
+ markersize=120,
254
+ color="green",
255
+ )
256
+ )
257
+ if has_sell_signals:
258
+ apds.append(
259
+ mpf.make_addplot(
260
+ sell_signal,
261
+ type="scatter",
262
+ marker="v",
263
+ markersize=120,
264
+ color="red",
265
+ )
266
+ )
267
+
268
+ # If no trades found in the date range, warn the user
269
+ if not apds:
270
+ import warnings
271
+ warnings.warn(
272
+ "No trades found in the specified date range. "
273
+ "Plotting price data without trade markers."
274
+ )
271
275
 
272
276
  # Generate default title if not provided
273
277
  if title is None:
@@ -282,6 +286,7 @@ class BacktestReport:
282
286
  figsize=figsize,
283
287
  style=style,
284
288
  title=title,
289
+ warn_too_much_data=len(data) + 5
285
290
  )
286
291
 
287
292
  def __str__(self) -> str:
File without changes
File without changes
File without changes
File without changes
File without changes