Zipline live portfolio not updated when stop order executes

Hi Brian,

Please forgive the frequent posts as I iron out the final kinks of zipline live!

I'm finding that the context.portfolio object is not updated when one of my stop orders is filled. More specifically, I opened a short position with an MKT order and simultaneously opened a STOP buy order to cover it. The stop order triggered about an hour later. The execution of both orders appeared in flightlog and is confirmed when I query the positions in my account (the order statuses shows as filled, and the short position no longer exists, as it was covered by the stop).

However, within the zipline strategy still running, context.portfolio shows that the short position is still open. This is only corrected when I cancel the strategy and start it again - I assume because the context.portfolio is refreshed every time the strategy starts.

I can replicate this by opening a position in a zipline live strategy with an zipline.api.order() command and then closing it outside of zipline using quantrocket.blotter.place_orders() in a notebook. The closing order executes, but the change in position is not recognized within the zipline strategy in real-time.

Lack of real-time portfolio update is problematic for a number of reasons. Suggestions for workaround?

As per the docs, context.portfolio isn’t supposed to represent your actual brokerage portfolio but only what’s happening in your Zipline strategy. So if you’re placing related orders outside of Zipline, you’re tricking it. You should place all related orders from within the strategy itself, or else be prepared to cancel and restart the strategy if you want outside orders to be picked up.

I only placed the orders outside of zipline to manually test the refresh within the strategy. The original problem occurred with a stop trade executed from within the strategy.

Part of the difficulty in debugging zipline live is that replicating some of the errors requires specific market conditions (e.g. triggering a stop price) that can't be forced to happen in the live context.

I'll try to find another instance of this happening or come up with a better way to replicate it.

Yes, a minimal example algorithm that reproduces the issue would be the next step. Using the simple template below to place a market and a stop order which fills later, everything is updated properly. Nor is there any difference in the order monitoring mechanism for a market order vs a stop order.

import zipline.api as algo
from zipline.finance.execution import StopOrder

def initialize(context):
    context.invested = False

def handle_data(context, data):

    print("current portfolio:")
    print(context.portfolio)

    print("open orders:")
    print(algo.get_open_orders())

    if not context.invested:
        gm = algo.sid("FIBBG000NDYB67")
        algo.order_target(gm, 100)
        
        style = StopOrder(49.08)
        algo.order_target(gm, -100, style=style)
        context.invested = True