Zipline
Ordering
Placing Orders
Both Quantopian and QuantConnect offer several methods for placing orders. Both platforms have
MarketOrder
, LimitOrder
, StopOrder
, and StopLimitOrder
stop_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]) -> 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
set_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 Portfolio
portfolio
, then
manually determine the new target percent to pass to SetHoldings
set_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 Portfolio
portfolio
class provides read-only access to the current portfolio state. The state
includes starting cash, current cash, portfolio value, and positions. The Portfolio
portfolio
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 Portfolio
portfolio
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 Portfolio
portfolio
on QuantConnect is a Dictionary<Symbol, SecurityHolding>
, we can
get information on current positions by indexing the Portfolio
portfolio
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 Portfolio
portfolio
object refer to the
Securities and Portfolio documentation.