Skip to content

Commit 49b799b

Browse files
committed
feat(strategy): port backtest simulator improvements into main
Bring the backtest simulator improvements into main without the broker/live system: trailing-stop activation-level fills, qty_percent exit-leg re-arm prevention, intraday filled-order cap flatten/latch, risk-rule enforcement (max_drawdown, max_intraday_loss, max_cons_loss_days), gap-open and multi-bracket OCA fill ordering, same-bar exit fill priority, and lot-size rounding. Split the single Position class into PositionBase (abstract) and SimPosition; wire core/script.py and core/strategy_stats.py onto the new types. Add the _strategy_suppressed and _is_live lib flags the simulator references, and a _create_24_7_sessions() helper on CCXTProvider (get_opening_hours_and_sessions delegates to it) for the new tests. Add 11 strategy regression tests covering the ported behaviour.
1 parent 3646ee7 commit 49b799b

17 files changed

Lines changed: 1881 additions & 230 deletions

src/pynecore/core/script.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ class Script:
104104
use_bar_magnifier: bool = True
105105
fill_orders_on_standard_ohlc: bool = False
106106

107-
position: _strategy.Position = None # type: ignore[assignment]
107+
position: _strategy.PositionBase = None # type: ignore[assignment]
108108

109109
_modified: set[str] = field(default_factory=set)
110110

@@ -472,7 +472,7 @@ def strategy(
472472
script.dynamic_requests = dynamic_requests
473473
script.behind_chart = behind_chart
474474

475-
script.position = _strategy.Position()
475+
script.position = _strategy.SimPosition()
476476

477477
return script._decorate()
478478

src/pynecore/core/strategy_stats.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from ..types.na import NA
1212
from ..lib.strategy import Trade
1313
from .csv_file import CSVWriter
14-
from ..lib.strategy import Position
14+
from ..lib.strategy import PositionBase
1515

1616

1717
@dataclass
@@ -185,7 +185,7 @@ def to_dict(self) -> dict[str, float | int]:
185185

186186

187187
def calculate_strategy_statistics(
188-
position: Position,
188+
position: PositionBase,
189189
initial_capital: float,
190190
equity_curve: list[float] | None = None,
191191
first_price: float | None = None,
@@ -194,7 +194,7 @@ def calculate_strategy_statistics(
194194
"""
195195
Calculate comprehensive strategy statistics from position data.
196196
197-
:param position: Position object containing all trade data
197+
:param position: PositionBase object containing all trade data
198198
:param initial_capital: Initial capital for percentage calculations
199199
:param equity_curve: List of equity values for Sharpe/Sortino calculations
200200
:param first_price: First price for buy & hold calculation

src/pynecore/lib/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,12 @@
108108
# Lib semaphore - to prevent lib`s main function to do things it must not (plot, strategy things, etc.)
109109
_lib_semaphore = False
110110

111+
# Live trading mode flag — set by run.py when --live is specified
112+
_is_live = False
113+
114+
# Strategy suppression — prevents strategy order placement during historical phase in live mode
115+
_strategy_suppressed = False
116+
111117
#
112118
# Callable modules
113119
#

0 commit comments

Comments
 (0)