Quantopian's community platform is shutting down. Please read this post for more information and download your code.
Back to Community
Bracket Orders

Hello Everyone,

Does Quantopian support Bracket Orders? and Bracket Orders with stop-limit?

It would also be interesting if we could group the algorithms into folders or packages

3 responses

Not directly, but they can be coded in. See here: https://www.quantopian.com/help#ide-ordering

You can see we support limit and stop orders. I believe for a bracketed order, you would want to issue a buy order accompanied by a stop and a limit order. You would also need to be able to check the status of the stop and limit orders each bar so that you could cancel the other order. You could do this by storing the order id of your stop and limit orders and checking on them every bar after you ordered. Something like this:

order(context.sid, -50)  
context.stop_order = order(context.sid, 50, style=StopOrder(30))  
context.limit_order = order(context.sid, 50, style=LimitOrder(20))  

Then on subsequent runs of handle_data, you would run:

if context.stop_order.stop_reached:  
    cancel_order(context.limit_order)  
if context.limit_order.limit_reached:  
    cancel_order(context.stop_order)  

I'm not too familiar with bracketed orders, but hopefully that helps!

Disclaimer

The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by Quantopian. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. No information contained herein should be regarded as a suggestion to engage in or refrain from any investment-related course of action as none of Quantopian nor any of its affiliates is undertaking to provide investment advice, act as an adviser to any plan or entity subject to the Employee Retirement Income Security Act of 1974, as amended, individual retirement account or individual retirement annuity, or give advice in a fiduciary capacity with respect to the materials presented herein. If you are an individual retirement or other investor, contact your financial advisor or other fiduciary unrelated to Quantopian about whether any given investment idea, strategy, product or service described herein may be appropriate for your circumstances. All investments involve risk, including loss of principal. Quantopian makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances.

Thanks Gus that is what I was doing, for a single order it is simple but for multiple orders I ended up having most of my code just to manage my orders and the strategy hidden in between.
It would be nice if the system provided and abstraction for these orders, Bracket, Trailing Order

Here are the orders supported by IB
https://www.interactivebrokers.com/en/software/webtraderguide/webtrader/orders/supported_order_types.htm

Hello,

I've send this feature request https://github.com/quantopian/zipline/issues/366 some months ago.

I'm trying to implement it myself using 2 classes one named BracketOrder and one named BOBottler.

BOBottler is responsible of giving pseudo ticket for BO order (each BO order being composed of 3 orders)
For now I'm just considering that first order (I will call it master order) is a market order.


class BracketOrder(object):  
    ticket = None  
    symbol = None  
    volume = None

    price_SL = None  
    price_TP = None  
    price_open = None  
    # for stats  
    #price_close = None

    def __init__(self, context, symbol, volume, price_stop, price_limit): #, syle=None, price_open=None):  
        self.context = context  
        self.symbol = symbol  
        self.volume = volume  
        self.price_stop = price_stop  
        self.price_limit = price_limit  
        self.order_id_master = None  
        self.order_id_limit = None  
        self.order_id_stop = None  
        #self.price_open = price_open  
        #self.style = ... # for now order 1 is only a market order  
    def execute(self):  
        self.order_id_master = order(self.symbol, self.volume)  
        self.order_id_limit = order(self.symbol, -self.volume, style=StopOrder(self.price_stop))  
        self.order_id_stop = order(self.symbol, -self.volume, style=LimitOrder(self.price_limit))  
        return(self.order_id_master)  
    def __repr__(self):  
        s = "<BO ticket=%s price_limit=%s price_stop=%s>" % (self.ticket, self.price_limit, self.price_stop)  
        return(s)

class BOBottler(object):  
    _ticket = 100000  
    data = None  
    _d_orders = {}  
    def __init__(self, context):  
        self.context = context

    def ticket(self):  
        self._ticket += 1  
        return(self._ticket)  
    def update(self, data):  
        self.data = data  
        self.watch_orders_to_cancel()

    def order_send(self, symbol, volume, price_SL, price_TP):  
        bo = BracketOrder(self.context, symbol, volume, price_SL, price_TP)  
        order_id_master = bo.execute()  
        bo.ticket = self.ticket()  
        self._d_orders[bo.ticket] = bo  
        return(bo.ticket)  
    def order_close(self, ticket):  
        pass  
    def order_cancel(self, ticket):  
        pass  
    def watch_orders_to_cancel(self):  
        for tkt, bo in self._d_orders.items():  
            order_stop = get_order(bo.order_id_stop)  
            order_limit = get_order(bo.order_id_limit)  
            if order_stop.stop_reached:  
                cancel_order(bo.order_id_limit)  
                print("cancel limit_order %s" % bo.order_id_limit)  
            if order_limit.limit_reached:  
                cancel_order(bo.order_id_stop)  
                print("cancel stop_order %s" % bo.order_id_stop)  
def initialize(context):  
    #context.symb = sid(24) # AAPL  
    context.symb = symbol('AAPL')  
    context.first_time = True  
    #context.orders = {}  
    #context._ticket = 10000  
    context.bottler = BOBottler(context)  
    context.i = 0

# Will be called on every trade event for the securities you specify.  
def handle_data(context, data):  
    # Implement your algorithm logic here.

    # data[sid(X)] holds the trade event data for that security.  
    # context.portfolio holds the current portfolio state.

    # Place orders with the order(SID, amount) method.

    # TODO: implement your own logic here.  
    context.bottler.update(data)  
    if context.first_time:  
        volume = 50  
        p = data[context.symb].price  
        symb = context.symb  
        pSL = p*0.8  
        pTP = p*1.2  
        print("price=%s SL=%s TP=%s" % (p, pSL, pTP))  
        tkt = context.bottler.order_send(symb, volume, pSL, pTP)  
        #bo = BracketOrder(context, symb, volume, pSL, pTP)  
        #(tkt, order_id_1, order_id_SL, order_id_TP) = bo.execute()  
        print("ticket=%s" % tkt)  
        #context.orders[order_id] = True  
        context.first_time = False  
    context.i += 1  
    #if context.i == 20:  
    #   raise(NotImplementedError)

#def finalize(context):  
#    print("end of backtest")  
# should be fine to display some stats into log !  

but I'm having some difficulties to write the watch_orders_to_cancel method.

Any help is welcome.

An other interesting feature is support of OCA orders see also https://www.quantopian.com/posts/oca-orders
because if first order of market is a limit order and it's cancelled, limit order (take profit) and stop order (stop loss) should
also be canceled.

So maybe we first need OCA order support before BO order support.

PS: edited: see https://www.quantopian.com/posts/a-framework-to-manage-bracket-orders-with-sl-tp-and-additional-features-trailingstop-breakeven-expiration-and-advanced-statistics