Zipline
Ordering
Placing Orders
Both Quantopian and QuantConnect offer several methods for placing orders. Both platforms have
MarketOrder, LimitOrder, StopOrder, and StopLimitOrderstop_limit_order 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]):
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 SetHoldingsset_holdings 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 SetHoldingsset_holdings.
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.