Zipline

Ordering

Placing Orders

Both Quantopian and QuantConnect offer several methods for placing orders. Both platforms have MarketOrder, LimitOrder, StopOrder, and StopLimitOrder classes to create specific order types, although the StopOrder order is named StopMarketOrder on our platform. On Quantopian, creating these orders is done by passing a style argument to the order method.

from zipline.finance.execution import (
    LimitOrder,
    MarketOrder,
    StopLimitOrder,
    StopOrder,
)

def initialize(context):
    context.stock = sid(8554)
    context.ordered = False

def handle_data(context, data):
    if not context.ordered:
        close = data.current(context.stock, 'close')
        order(context.stock, 10, style=MarketOrder()) 
        order(context.stock, 10, style=LimitOrder(limit_price=close * 0.9)) 
        order(context.stock, -10, style=StopOrder(stop_price=close * 0.85)) 
        order(context.stock, -10, style=StopLimitOrder(limit_price=close * 0.75, stop_price=close * 0.85)) 
        context.ordered = True

On QuantConnect, the same orders can be created with

class MyAlgorithm(QCAlgorithm):

    def initialize(self) -> None:
        self.set_start_date(2020, 3, 1)
        self.set_cash(100000)
        self._symbol = self.add_equity("SPY", Resolution.MINUTE).symbol
        self.ordered = False

    def on_data(self, slice: Slice) -> None:
        if not self.ordered and slice.contains_key(self.symbol):
            close = slice[self.symbol].close
            self.market_order(self.symbol, 10)
            self.limit_order(self.symbol, 10, close * 0.9)
            self.stop_market_order(self.symbol, -10, close * 0.85)
            self.stop_limit_order(self.symbol, -10, close * 0.85, close * 0.75)
            self.ordered = True

In addition to the order types above, QuantConnect has several other order types available. Refer to our Trading and Orders documentation for a comprehensive list.

Quantopian's order_optimal_portfolio method computes the optimal portfolio weights using an objective and constraints, then places the orders to achieve the desired portfolio. For example, the code below uses the Quantopian API to create an equal-weighted dollar-neutral portfolio.

import quantopian.algorithm as algo
import quantopian.optimize as opt

objective = opt.TargetWeights(weights)
constraints = [
    opt.MaxGrossExposure(1.0),
    opt.DollarNeutral()
]
algo.order_optimal_portfolio(objective, constraints)

To acheive the same functionality with QuantConnect, we utilize portfolio construction models. For instance, to create an equal-weighted dollar-neutral portfolio, we could define the following portfolio construction model and attach it to the algorithm.

class MyAlgorithm(QCAlgorithm):
    def initialize(self) -> None:
        self.set_start_date(2020, 5, 1)  
        self.set_cash(100000)  

        self.set_portfolio_construction(EqualWeightedDollarNeutralPortfolioConstructionModel())


class EqualWeightedDollarNeutralPortfolioConstructionModel(PortfolioConstructionModel):

    def determine_target_percent(self, activeInsights: List[Insight]) -> Dict[Insight, float]:
        result = {}
        
        longs = 0
        shorts = 0
        for insight in activeInsights:
            if insight.direction == InsightDirection.UP:
                longs += 1
            elif insight.direction == InsightDirection.DOWN:
                shorts += 1
            result[insight] = 0
        
        if longs == 0 or shorts == 0:
            return result
        
        for insight in activeInsights:
            if insight.direction == InsightDirection.UP:
                result[insight] = 0.5 / longs
            elif insight.direction == InsightDirection.DOWN:
                result[insight] = -0.5 / shorts
        return result

When algorithms require manual control of their orders, both Quantopian and QuantConnect have lower-level ordering methods. Quantopian's order method, which places an order for a fixed number of shares, directly maps to our Order method. Additionally, Quantopian's order_target_percent method places an order to adjust a position to a target percent of the current portfolio value. Here's an example use case of these methods on the Quantopian platform.

order_target_percent(sid(8554), 10) # Allocate 10% of portfolio
order(sid(8554), 10) # Order 10 shares

On QuantConnect, these same orders can be placed using the SetHoldings and Order methods.

self.set_holdings(symbol, 0.1) # Allocate 10% of portfolio
self.order(symbol, 10) # Order 10 shares

Quantopian and QuantConnect don't have equivalents for all the ordering techniques, although we can create a workaround for most situations. For instance, Quantopian's order_percent method places an order in the specified asset corresponding to the given percent of the current portfolio value.

order_percent(sid(8554), 10) # Allocate 10% more of portfolio

To accomplish this on QuantConnect, we can determine the weight of the asset in the Portfolioportfolio, then manually determine the new target percent to pass to SetHoldings.

current_weight = self.portfolio[symbol].holdings_value / self.portfolio.total_portfolio_value
self.set_holdings(symbol, current_weight + 0.1) # Allocate 10% more of portfolio

The Porfolio Object

Quantopian's Portfolioportfolio class provides read-only access to the current portfolio state. The state includes starting cash, current cash, portfolio value, and positions. The Portfolioportfolio object is accessed through the context object, as seen below.

  
context.portfolio.starting_cash     # Amount of cash in the portfolio at the start of the backtest
                 .cash              # Amount of cash currently held in portfolio
                 .portfolio_value   # Current liquidation value of the portfolio's holdings
                 .positions         # Dict-like object for currently-held positions

All of this information, and more, is attainable on QuantConnect by using our Portfolioportfolio object. Listed below is an example of doing so. Although there isn't a property for starting cash, this value can be saved during Initialization to be referenced later.

self.portfolio.cash                  # Sum of all currencies in account (only settled cash)
              .total_portfolio_value   # Portfolio equity
              .keys                  # Collection of Symbol objects in the portfolio
              .values                # Collection of SecurityHolding objects in the portfolio

On Quantopian, by iterating through the positions dictionary, we can access information about currently-held positions. This includes the number of shares held, the last traded price & date of the asset, and the position's cost basis.

  
for sid, position in context.portfolio.positions.iteritems():
    position.amount            # Number of shares in the position 
            .cost_basis        # Volume weighted average price paid per share
            .last_sale_price   # Price at last sale of the asset on the exchange 
            .last_sale_date    # Date of last sale of the asset on the exchange

Since the Portfolioportfolio on QuantConnect is a Dictionary<Symbol, SecurityHolding>, we can get information on current positions by indexing the Portfolioportfolio object with a Symbol or ticker. The SecurityHolding object that is returned contains information related to a single security in the portfolio. For instance, we have

self.portfolio[symbol].quantity                 # Number of shares held
                      .average_price             # Average price of shares held (aka cost basis)
                      .price                    # Last traded price of the security

For more information on our Portfolioportfolio object refer to the Securities and Portfolio documentation.

You can also see our Videos. You can also get in touch with us via Discord.

Did you find this page helpful?

Contribute to the documentation: