Repository navigation
Replies: 2 comments
|
Partial answer, being upfront about the boundary: I verified the pieces that exist and the right mechanism for the rest, but I haven't run a full working version of your exact spec, so I'd rather hand you the correct building blocks than a complete callback I can't vouch for end to end. What's native: trailing stop-loss is real and built in — What isn't native: there's no The right hook for the custom part: What vectorbt doesn't model at all: parent/child order lifecycle, OCO cancellation, and time-in-force on a pending limit entry. vectorbt is a vectorized signal-based backtester, not an order-book/broker simulator — there's no concept of an unfilled limit order sitting in a queue waiting to trigger the rest of the bracket. If the limit-entry-with-TIF part is a hard requirement (not just "buy now, then bracket"), that's a different kind of tool (an event-driven backtester modeling actual order state) rather than something to bolt onto |
|
This runs end to end on vectorbt 1.1.1, the current release, and covers your spec except a real resting order book. Three details of import numpy as np, vectorbt as vbt
from numba import njit
@njit
def sl_dollar(c, trail): # level = running high - trail
if np.isnan(c.curr_stop):
return c.curr_stop, c.curr_trail
return trail / c.curr_price, True
@njit
def tp_over_sl(c, high, trail, addon): # level = (running high - trail) + addon
if np.isnan(c.curr_stop):
return c.curr_stop
peak = c.init_price
for j in range(c.init_i + 1, c.i): # the bars the trailing reference has seen
peak = max(peak, high[j, c.col])
return (peak - trail + addon) / c.init_price - 1.0
def bracket(open_, high, low, close, signal, limit=100.0, tif=5, trail=5.0, addon=15.0):
entries = np.zeros(len(close), bool)
price = close.to_numpy().copy()
armed_until = -1
for i in range(len(close)): # parent: limit buy, valid for `tif` bars
if signal.iloc[i]:
armed_until = i + tif
if i <= armed_until and low.iloc[i] <= limit:
entries[i], price[i], armed_until = True, min(open_.iloc[i], limit), -1
return vbt.Portfolio.from_signals(
close, entries=entries, exits=False, price=price,
open=open_, high=high, low=low, size=1, init_cash=10_000,
sl_stop=trail / limit, sl_trail=True, tp_stop=(addon - trail) / limit,
adjust_sl_func_nb=sl_dollar, adjust_sl_args=(trail,),
adjust_tp_func_nb=tp_over_sl, adjust_tp_args=(high.to_numpy()[:, None], trail, addon))On three test paths it buys at 100 and exits at 107 after a 112 high (trailing stop), buys at 100 and exits at 116 when a bar jumps from a 106 high to 117 (take-profit), and doesn't trade when the low only reaches 100 after the window. Note what the spec implies: the TP sits $10 above the running high, so it only fills on a bar that jumps more than $10 past the previous high. |
Uh oh!
There was an error while loading. Please reload this page.
Hi all,
In vectorbt how can we implement the following bracket order?
For a long trade on a stock that is currently trading at 110 USD, send three orders:
Thanks
All reactions