Skip to content

Commit 8a71452

Browse files
committed
Allow canceling submitted broker orders
1 parent d35750e commit 8a71452

4 files changed

Lines changed: 28 additions & 14 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ An enhanced version of the backtrader Python library for quantitative trading an
4949
- Trade statistics and performance metrics
5050
- PyFolio integration
5151
- 🎯 **Flexible Order Types**: Market, Limit, Stop, Stop-Limit, OCO orders
52+
- 🔁 **Cancelable Submitted Orders**: Orders that have been submitted but not yet accepted by the broker can be canceled, matching event-driven broker behavior for strategies that adjust protective stop/limit orders within the same cycle.
5253
- 💼 **Position Sizing**: Built-in position sizers and custom sizing strategies
5354
- 📉 **Data Processing**: Resampling, replaying, and multi-timeframe analysis
5455

backtrader/brokers/bbroker.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -448,10 +448,23 @@ def get_fundvalue(self):
448448

449449
# 取消订单
450450
def cancel(self, order, bracket=False):
451-
try:
452-
self.pending.remove(order)
453-
except ValueError:
454-
# If the list didn't have the element we didn't cancel anything
451+
if order is None or not order.alive():
452+
return False
453+
454+
if order.status not in (Order.Submitted, Order.Accepted, Order.Partial):
455+
return False
456+
457+
removed = False
458+
for queue in (self.pending, self.submitted):
459+
try:
460+
queue.remove(order)
461+
except ValueError:
462+
continue
463+
removed = True
464+
break
465+
466+
if not removed:
467+
# If neither queue had the element we didn't cancel anything
455468
return False
456469

457470
order.cancel()

scripts/run_strategy_branch_compare.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
"run_id",
2222
}
2323

24-
DEFAULT_BRANCHES = ["current", "dev"]
24+
DEFAULT_BRANCHES = ["current", "master"]
2525
LOG_FILE_NAMES = {
2626
"bar.log",
2727
"error.log",
@@ -73,7 +73,7 @@ def parse_args() -> argparse.Namespace:
7373
action="append",
7474
help=(
7575
"Branch/ref to run. Use 'current' for the current working tree including uncommitted changes. "
76-
"Can be repeated. Default: current and dev."
76+
"Can be repeated. Default: current and master."
7777
),
7878
)
7979
parser.add_argument("--timeout", type=int, default=300, help="Timeout for run.py in seconds.")

tests/strategies/test_05_stop_order_strategy.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -625,14 +625,14 @@ def test_stop_order_strategy():
625625
# Assert test results (exact values)
626626
# Tolerance: 1e-6 for most metrics, 0.01 for final_value
627627
assert strat.bar_num == 4414, f"Expected bar_num=4414, got {strat.bar_num}"
628-
assert strat.buy_count == 4, f"Expected buy_count=4, got {strat.buy_count}"
629-
assert strat.sell_count == 1, f"Expected sell_count=1, got {strat.sell_count}"
630-
assert strat.stop_count == 3, f"Expected stop_count=3, got {strat.stop_count}"
631-
assert total_trades == 5, f"Expected total_trades=5, got {total_trades}"
632-
assert abs(sharpe_ratio - (-0.11532400124757156)) < 1e-6, f"Expected sharpe_ratio=-0.11532400124757156, got {sharpe_ratio}"
633-
assert abs(annual_return - (-0.02594445655033843)) < 1e-6, f"Expected annual_return=-0.02594445655033843, got {annual_return}"
634-
assert abs(max_drawdown - 0.75241098463008) < 1e-6, f"Expected max_drawdown=0.75241098463008, got {max_drawdown}"
635-
assert abs(final_value - 62969.156504940926) < 0.01, f"Expected final_value=62969.156504940926, got {final_value}"
628+
assert strat.buy_count == 211, f"Expected buy_count=211, got {strat.buy_count}"
629+
assert strat.sell_count == 104, f"Expected sell_count=104, got {strat.sell_count}"
630+
assert strat.stop_count == 106, f"Expected stop_count=106, got {strat.stop_count}"
631+
assert total_trades == 210, f"Expected total_trades=210, got {total_trades}"
632+
assert abs(sharpe_ratio - (-0.7549783580584405)) < 1e-6, f"Expected sharpe_ratio=-0.7549783580584405, got {sharpe_ratio}"
633+
assert abs(annual_return - (-0.14437349885291842)) < 1e-6, f"Expected annual_return=-0.14437349885291842, got {annual_return}"
634+
assert abs(max_drawdown - 0.9428371118168646) < 1e-6, f"Expected max_drawdown=0.9428371118168646, got {max_drawdown}"
635+
assert abs(final_value - 6434.648954130735) < 0.01, f"Expected final_value=6434.648954130735, got {final_value}"
636636

637637
print("\nAll tests passed!")
638638

0 commit comments

Comments
 (0)