From d888c4faaa15a14850bd227dd8bb6d62d5a3f575 Mon Sep 17 00:00:00 2001 From: Joe Jevnik Date: Thu, 5 May 2016 14:16:30 -0400 Subject: [PATCH] DOC: update docs for api functions --- docs/source/appendix.rst | 136 ++++++- tests/test_algorithm.py | 4 +- zipline/algorithm.py | 648 +++++++++++++++++++++++++++---- zipline/api.py | 35 +- zipline/finance/cancel_policy.py | 31 +- zipline/finance/commission.py | 26 +- zipline/finance/slippage.py | 34 +- zipline/sources/requests_csv.py | 12 +- zipline/utils/events.py | 11 +- 9 files changed, 798 insertions(+), 139 deletions(-) diff --git a/docs/source/appendix.rst b/docs/source/appendix.rst index 1ef2ded5..800ac8ec 100644 --- a/docs/source/appendix.rst +++ b/docs/source/appendix.rst @@ -15,10 +15,142 @@ The following methods are available for use in the ``initialize``, In all listed functions, the ``self`` argument is implicitly the currently-executing :class:`~zipline.algorithm.TradingAlgorithm` instance. -.. automodule:: zipline.api +Scheduling Functions +```````````````````` + +.. autofunction:: zipline.api.schedule_function + +.. autoclass:: zipline.api.date_rules + :members: + :undoc-members: + +.. autoclass:: zipline.api.time_rules :members: -.. autoclass:: zipline.algorithm.TradingAlgorithm +Orders +`````` + +.. autofunction:: zipline.api.order + +.. autofunction:: zipline.api.order_value + +.. autofunction:: zipline.api.order_percent + +.. autofunction:: zipline.api.order_target + +.. autofunction:: zipline.api.order_target_value + +.. autofunction:: zipline.api.order_target_percent + +.. autoclass:: zipline.finance.execution.ExecutionStyle + :members: + +.. autoclass:: zipline.finance.execution.MarketOrder + +.. autoclass:: zipline.finance.execution.LimitOrder + +.. autoclass:: zipline.finance.execution.StopOrder + +.. autoclass:: zipline.finance.execution.StopLimitOrder + +.. autofunction:: zipline.api.get_order + +.. autofunction:: zipline.api.get_open_orders + +.. autofunction:: zipline.api.cancel_order + +Order Cancellation Policies +''''''''''''''''''''''''''' + +.. autofunction:: zipline.api.set_cancel_policy + +.. autoclass:: zipline.finance.cancel_policy.CancelPolicy + :members: + +.. autofunction:: zipline.api.EODCancel + +.. autofunction:: zipline.api.NeverCancel + + +Assets +`````` + +.. autofunction:: zipline.api.symbol + +.. autofunction:: zipline.api.symbols + +.. autofunction:: zipline.api.future_symbol + +.. autofunction:: zipline.api.future_chain + +.. autofunction:: zipline.api.set_symbol_lookup_date + +.. autofunction:: zipline.api.sid + + +Trading Controls +```````````````` + +Zipline provides trading controls to help ensure that the algorithm is +performing as expected. The functions help protect the algorithm from certian +bugs that could cause undesirable behavior when trading with real money. + +.. autofunction:: zipline.api.set_do_not_order_list + +.. autofunction:: zipline.api.set_long_only + +.. autofunction:: zipline.api.set_max_leverage + +.. autofunction:: zipline.api.set_max_order_count + +.. autofunction:: zipline.api.set_max_order_size + +.. autofunction:: zipline.api.set_max_position_size + + +Simulation Parameters +````````````````````` + +.. autofunction:: zipline.api.set_commission + +.. autoclass:: zipline.finance.commission.PerShare + +.. autoclass:: zipline.finance.commission.PerTrade + +.. autoclass:: zipline.finance.commission.PerDollar + +.. autofunction:: zipline.api.set_slippage + +.. autoclass:: zipline.finance.slippage.SlippageModel + :members: + +.. autoclass:: zipline.finance.slippage.FixedSlippage + +.. autoclass:: zipline.finance.slippage.VolumeShareSlippage + +.. autofunction:: zipline.api.set_benchmark + +Pipeline +```````` + +For more information, see :ref:`pipeline-api` + +.. autofunction:: zipline.api.attach_pipeline + +.. autofunction:: zipline.api.pipeline_output + + +Miscellaneous +````````````` + +.. autofunction:: zipline.api.record + +.. autofunction:: zipline.api.get_environment + +.. autofunction:: zipline.api.fetch_csv + + +.. _pipeline-api: Pipeline API ~~~~~~~~~~~~ diff --git a/tests/test_algorithm.py b/tests/test_algorithm.py index 8faa31ba..31f1cc38 100644 --- a/tests/test_algorithm.py +++ b/tests/test_algorithm.py @@ -161,7 +161,7 @@ from zipline.utils.api_support import ZiplineAPI, set_algo_instance from zipline.utils.context_tricks import CallbackManager from zipline.utils.control_flow import nullctx import zipline.utils.events -from zipline.utils.events import DateRuleFactory, TimeRuleFactory, Always +from zipline.utils.events import date_rules, time_rules, Always import zipline.utils.factory as factory from zipline.utils.tradingcalendar import trading_day, trading_days @@ -389,8 +389,6 @@ def handle_data(context, data): algo.run(self.data_portal) def test_schedule_function(self): - date_rules = DateRuleFactory - time_rules = TimeRuleFactory us_eastern = pytz.timezone('US/Eastern') def incrementer(algo, data): diff --git a/zipline/algorithm.py b/zipline/algorithm.py index 9b0026ce..4ab880dc 100644 --- a/zipline/algorithm.py +++ b/zipline/algorithm.py @@ -96,8 +96,8 @@ import zipline.utils.events from zipline.utils.events import ( EventManager, make_eventrule, - DateRuleFactory, - TimeRuleFactory, + date_rules, + time_rules, ) from zipline.utils.factory import create_simulation_parameters from zipline.utils.math_utils import ( @@ -764,6 +764,41 @@ class TradingAlgorithm(object): @api_method def get_environment(self, field='platform'): + """Query the execution environment. + + Parameters + ---------- + field : {'platform', 'arena', 'data_frequency', + 'start', 'end', 'capital_base', 'platform', '*'} + The field to query. The options have the following meanings: + arena : str + The arena from the simulation parameters. This will normally + be ``'backtest'`` but some systems may use this distinguish + live trading from backtesting. + data_frequency : {'daily', 'minute'} + data_frequency tells the algorithm if it is running with + daily data or minute data. + start : datetime + The start date for the simulation. + end : datetime + The end date for the simulation. + capital_base : float + The starting capital for the simulation. + platform : str + The platform that the code is running on. By default this + will be the string 'zipline'. This can allow algorithms to + know if they are running on the Quantopian platform instead. + + Returns + ------- + val : any + The value for the field queried. See above for more information. + + Raises + ------ + KeyError + Raised when ``field`` is not a valid option. + """ env = { 'arena': self.sim_params.arena, 'data_frequency': self.sim_params.data_frequency, @@ -778,7 +813,8 @@ class TradingAlgorithm(object): return env[field] @api_method - def fetch_csv(self, url, + def fetch_csv(self, + url, pre_func=None, post_func=None, date_column='date', @@ -789,6 +825,47 @@ class TradingAlgorithm(object): symbol_column=None, special_params_checker=None, **kwargs): + """Fetch a csv from a remote url. + + Parameters + ---------- + url : str + The url of the csv file to load. + pre_func : callable[pd.DataFrame -> pd.DataFrame], optional + A callback to allow preprocessing the raw data returned from + fetch_csv before dates are paresed or symbols are mapped. + post_func : callable[pd.DataFrame -> pd.DataFrame], optional + A callback to allow postprocessing of the data after dates and + symbols have been mapped. + date_column : str, optional + The name of the column in the preprocessed dataframe containing + datetime information to map the data. + date_format : str, optional + The format of the dates in the ``date_column``. If not provided + ``fetch_csv`` will attempt to infer the format. For information + about the format of this string, see :func:`pandas.read_csv`. + timezone : tzinfo or str, optional + The timezone for the datetime in the ``date_column``. + symbol : str, optional + If the data is about a new asset or index then this string will + be the name used to identify the values in ``data``. For example, + one may use ``fetch_csv`` to load data for VIX, then this field + could be the string ``'VIX'``. + mask : bool, optional + Drop any rows which cannot be symbol mapped. + symbol_column : str + If the data is attaching some new attribute to each asset then this + argument is the name of the column in the preprocessed dataframe + containing the symbols. This will be used along with the date + information to map the sids in the asset finder. + **kwargs + Forwarded to :func:`pandas.read_csv`. + + Returns + ------- + csv_data_source : zipline.sources.requests_csv.PandasRequestsCSV + A requests source that will pull data from the url specified. + """ # Show all the logs every time fetcher is used. csv_data_source = PandasRequestsCSV( @@ -816,8 +893,14 @@ class TradingAlgorithm(object): return csv_data_source def add_event(self, rule=None, callback=None): - """ - Adds an event to the algorithm's EventManager. + """Adds an event to the algorithm's EventManager. + + Parameters + ---------- + rule : EventRule + The rule for when the callback should be triggered. + callback : callable[(context, data) -> None] + The function to execute when the rule is triggered. """ self.event_manager.add_event( zipline.utils.events.Event(rule, callback), @@ -829,11 +912,26 @@ class TradingAlgorithm(object): date_rule=None, time_rule=None, half_days=True): + """Schedules a function to be called with some timed rules. + + Parameters + ---------- + func : callable[(context, data) -> None] + The function to execute when the rule is triggered. + date_rule : EventRule, optional + The rule for the dates to execute this function. + time_rule : EventRule, optional + The rule for the times to execute this function. + half_days : bool, optional + Should this rule fire on half days? + + See Also + -------- + :class:`zipline.api.date_rules` + :class:`zipline.api.time_rules` """ - Schedules a function to be called with some timed rules. - """ - date_rule = date_rule or DateRuleFactory.every_day() - time_rule = ((time_rule or TimeRuleFactory.market_open()) + date_rule = date_rule or date_rules.every_day() + time_rule = ((time_rule or time_rules.market_open()) if self.sim_params.data_frequency == 'minute' else # If we are in daily mode the time_rule is ignored. zipline.utils.events.Always()) @@ -845,8 +943,18 @@ class TradingAlgorithm(object): @api_method def record(self, *args, **kwargs): - """ - Track and record local variable (i.e. attributes) each day. + """Track and record values each day. + + Parameters + ---------- + **kwargs + The names and values to record. + + Notes + ----- + These values will appear in the performance packets and the performance + dataframe passed to ``analyze`` and returned from + :func:`~zipline.run_algorithm`. """ # Make 2 objects both referencing the same iterator args = [iter(args)] * 2 @@ -860,18 +968,48 @@ class TradingAlgorithm(object): self._recorded_vars[name] = value @api_method - def set_benchmark(self, benchmark_sid): + def set_benchmark(self, benchmark): + """Set the benchmark asset. + + Parameters + ---------- + benchmark : Asset + The asset to set as the new benchmark. + + Notes + ----- + Any dividends payed out for that new benchmark asset will be + automatically reinvested. + """ if self.initialized: raise SetBenchmarkOutsideInitialize() - self.benchmark_sid = benchmark_sid + self.benchmark_sid = benchmark @api_method @preprocess(symbol_str=ensure_upper_case) def symbol(self, symbol_str): - """ - Default symbol lookup for any source that directly maps the - symbol to the Asset (e.g. yahoo finance). + """Lookup an Equity by its ticker symbol. + + Parameters + ---------- + symbol_str : str + The ticker symbol for the equity to lookup. + + Returns + ------- + equity : Equity + The equity that held the ticker symbol on the current + symbol lookup date. + + Raises + ------ + SymbolNotFound + Raised when the symbols was not held on the current lookup date. + + See Also + -------- + :func:`zipline.api.set_symbol_lookup_date` """ # If the user has not set the symbol lookup date, # use the period_end as the date for sybmol->sid resolution. @@ -885,19 +1023,51 @@ class TradingAlgorithm(object): @api_method def symbols(self, *args): - """ - Default symbols lookup for any source that directly maps the - symbol to the Asset (e.g. yahoo finance). + """Lookup multuple Equities as a list. + + Parameters + ---------- + *args : iterable[str] + The ticker symbols to lookup. + + Returns + ------- + equities : list[Equity] + The equities that held the given ticker symbols on the current + symbol lookup date. + + Raises + ------ + SymbolNotFound + Raised when one of the symbols was not held on the current + lookup date. + + See Also + -------- + :func:`zipline.api.set_symbol_lookup_date` """ return [self.symbol(identifier) for identifier in args] @api_method - def sid(self, a_sid): + def sid(self, sid): + """Lookup an Asset by its unique asset identifier. + + Parameters + ---------- + sid : int + The unique integer that identifies an asset. + + Returns + ------- + asset : Asset + The asset with the given ``sid``. + + Raises + ------ + SidsNotFound + When a requested sid is not found and default_none=False. """ - Default sid lookup for any source that directly maps the integer sid - to the Asset. - """ - return self.asset_finder.retrieve_asset(a_sid) + return self.asset_finder.retrieve_asset(sid) @api_method @preprocess(symbol=ensure_upper_case) @@ -911,21 +1081,20 @@ class TradingAlgorithm(object): Returns ------- - Future - A Future object. + future : Future + The future that trades with the name ``symbol``. Raises ------ SymbolNotFound Raised when no contract named 'symbol' is found. - """ return self.asset_finder.lookup_future_symbol(symbol) @api_method @preprocess(root_symbol=ensure_upper_case) def future_chain(self, root_symbol, as_of_date=None): - """ Look up a future chain with the specified parameters. + """Look up a future chain with the specified parameters. Parameters ---------- @@ -938,7 +1107,7 @@ class TradingAlgorithm(object): Returns ------- - FutureChain + chain : FutureChain The future chain matching the specified parameters. Raises @@ -1031,12 +1200,34 @@ class TradingAlgorithm(object): @api_method @disallowed_in_before_trading_start(OrderInBeforeTradingStart()) - def order(self, asset, amount, + def order(self, + asset, + amount, limit_price=None, stop_price=None, style=None): - """ - Place an order using the specified parameters. + """Place an order. + + Parameters + ---------- + asset : Asset + The asset that this order is for. + amount : int + The amount of shares to order. If this is negative, this is the + number of shares to sell or short. + style : ExecutionStyle, optional + The execution style for the order. + + Returns + ------- + order_id : str + The unique identifier for this order. + + See Also + -------- + :class:`zipline.finance.execution.ExecutionStyle` + :func:`zipline.api.order_value` + :func:`zipline.api.order_percent` """ if not self._can_order_asset(asset): return None @@ -1119,21 +1310,40 @@ class TradingAlgorithm(object): @api_method @disallowed_in_before_trading_start(OrderInBeforeTradingStart()) - def order_value(self, asset, value, - limit_price=None, stop_price=None, style=None): - """ - Place an order by desired value rather than desired number of shares. - If the requested asset exists, the requested value is - divided by its price to imply the number of shares to transact. - If the Asset being ordered is a Future, the 'value' calculated - is actually the exposure, as Futures have no 'value'. + def order_value(self, + asset, + value, + limit_price=None, + stop_price=None, + style=None): + """Place an order by desired value rather than desired number of + shares. - value > 0 :: Buy/Cover - value < 0 :: Sell/Short - Market order: order(sid, value) - Limit order: order(sid, value, limit_price) - Stop order: order(sid, value, None, stop_price) - StopLimit order: order(sid, value, limit_price, stop_price) + Parameters + ---------- + asset : Asset + The asset that this order is for. + value : float + If the requested asset exists, the requested value is + divided by its price to imply the number of shares to transact. + If the Asset being ordered is a Future, the 'value' calculated + is actually the exposure, as Futures have no 'value'. + + value > 0 :: Buy/Cover + value < 0 :: Sell/Short + style : ExecutionStyle + The execution style for the order. + + Returns + ------- + order_id : str + The unique identifier for this order. + + See Also + -------- + :class:`zipline.finance.execution.ExecutionStyle` + :func:`zipline.api.order` + :func:`zipline.api.order_percent` """ if not self._can_order_asset(asset): return None @@ -1197,8 +1407,17 @@ class TradingAlgorithm(object): @api_method def get_datetime(self, tz=None): - """ - Returns the simulation datetime. + """Returns the current simulation datetime. + + Parameters + ---------- + tz : tzinfo or str, optional + The timezone to return the datetime in. This defaults to utc. + + Returns + ------- + dt : datetime + The current simulation datetime converted to ``tz``. """ dt = self.datetime assert dt.tzinfo == pytz.utc, "Algorithm should have a utc datetime" @@ -1220,6 +1439,17 @@ class TradingAlgorithm(object): @api_method def set_slippage(self, slippage): + """Set the slippage model for the simulation. + + Parameters + ---------- + slippage : SlippageModel + The slippage model to use. + + See Also + -------- + :class:`zipline.finance.slippage.SlippageModel` + """ if not isinstance(slippage, SlippageModel): raise UnsupportedSlippageModel() if self.initialized: @@ -1228,6 +1458,19 @@ class TradingAlgorithm(object): @api_method def set_commission(self, commission): + """Sets the commision model for the simulation. + + Parameters + ---------- + commision : PerShare, PerTrade, or PerDollar + The commision model to use. + + See Also + -------- + :class:`zipline.finance.commission.PerShare` + :class:`zipline.finance.commission.PerTrade` + :class:`zipline.finance.commission.PerDollar` + """ if not isinstance(commission, (PerShare, PerTrade, PerDollar)): raise UnsupportedCommissionModel() @@ -1237,6 +1480,18 @@ class TradingAlgorithm(object): @api_method def set_cancel_policy(self, cancel_policy): + """Sets the order cancellation policy for the simulation. + + Parameters + ---------- + cancel_policy : CancelPolicy + The cancellation policy to use. + + See Also + -------- + :class:`zipline.api.EODCancel` + :class:`zipline.api.NeverCancel` + """ if not isinstance(cancel_policy, CancelPolicy): raise UnsupportedCancelPolicy() @@ -1247,10 +1502,14 @@ class TradingAlgorithm(object): @api_method def set_symbol_lookup_date(self, dt): - """ - Set the date for which symbols will be resolved to their assets + """Set the date for which symbols will be resolved to their assets (symbols may map to different firms or underlying assets at different times) + + Parameters + ---------- + dt : datetime + The new symbol lookup date. """ try: self._symbol_lookup_date = pd.Timestamp(dt, tz='UTC') @@ -1270,13 +1529,35 @@ class TradingAlgorithm(object): @api_method @disallowed_in_before_trading_start(OrderInBeforeTradingStart()) - def order_percent(self, asset, percent, - limit_price=None, stop_price=None, style=None): - """ - Place an order in the specified asset corresponding to the given + def order_percent(self, + asset, + percent, + limit_price=None, + stop_price=None, + style=None): + """Place an order in the specified asset corresponding to the given percent of the current portfolio value. - Note that percent must expressed as a decimal (0.50 means 50\%). + Parameters + ---------- + asset : Asset + The asset that this order is for. + percent : float + The percentage of the porfolio value to allocate to ``asset``. + This is specified as a decimal, for example: 0.50 means 50%. + style : ExecutionStyle + The execution style for the order. + + Returns + ------- + order_id : str + The unique identifier for this order. + + See Also + -------- + :class:`zipline.finance.execution.ExecutionStyle` + :func:`zipline.api.order` + :func:`zipline.api.order_value` """ if not self._can_order_asset(asset): return None @@ -1289,14 +1570,53 @@ class TradingAlgorithm(object): @api_method @disallowed_in_before_trading_start(OrderInBeforeTradingStart()) - def order_target(self, asset, target, - limit_price=None, stop_price=None, style=None): - """ - Place an order to adjust a position to a target number of shares. If + def order_target(self, + asset, + target, + limit_price=None, + stop_price=None, + style=None): + """Place an order to adjust a position to a target number of shares. If the position doesn't already exist, this is equivalent to placing a new order. If the position does exist, this is equivalent to placing an order for the difference between the target number of shares and the current number of shares. + + Parameters + ---------- + asset : Asset + The asset that this order is for. + target : int + The desired number of shares of ``asset``. + style : ExecutionStyle + The execution style for the order. + + Returns + ------- + order_id : str + The unique identifier for this order. + + + Notes + ----- + ``order_target`` does not take into account any open orders. For + example: + + .. code-block:: python + + order_target(sid(0), 10) + order_target(sid(0), 10) + + This code will result in 20 shares of ``sid(0)`` because the first + call to ``order_target`` will not have been filled when the second + ``order_target`` call is made. + + See Also + -------- + :class:`zipline.finance.execution.ExecutionStyle` + :func:`zipline.api.order` + :func:`zipline.api.order_target_percent` + :func:`zipline.api.order_target_value` """ if not self._can_order_asset(asset): return None @@ -1316,16 +1636,54 @@ class TradingAlgorithm(object): @api_method @disallowed_in_before_trading_start(OrderInBeforeTradingStart()) - def order_target_value(self, asset, target, - limit_price=None, stop_price=None, style=None): - """ - Place an order to adjust a position to a target value. If + def order_target_value(self, + asset, + target, + limit_price=None, + stop_price=None, + style=None): + """Place an order to adjust a position to a target value. If the position doesn't already exist, this is equivalent to placing a new order. If the position does exist, this is equivalent to placing an order for the difference between the target value and the current value. If the Asset being ordered is a Future, the 'target value' calculated is actually the target exposure, as Futures have no 'value'. + + Parameters + ---------- + asset : Asset + The asset that this order is for. + target : float + The desired total value of ``asset``. + style : ExecutionStyle + The execution style for the order. + + Returns + ------- + order_id : str + The unique identifier for this order. + + Notes + ----- + ``order_target_value`` does not take into account any open orders. For + example: + + .. code-block:: python + + order_target_value(sid(0), 10) + order_target_value(sid(0), 10) + + This code will result in 20 dollars of ``sid(0)`` because the first + call to ``order_target_value`` will not have been filled when the + second ``order_target_value`` call is made. + + See Also + -------- + :class:`zipline.finance.execution.ExecutionStyle` + :func:`zipline.api.order` + :func:`zipline.api.order_target` + :func:`zipline.api.order_target_percent` """ if not self._can_order_asset(asset): return None @@ -1340,14 +1698,48 @@ class TradingAlgorithm(object): @disallowed_in_before_trading_start(OrderInBeforeTradingStart()) def order_target_percent(self, asset, target, limit_price=None, stop_price=None, style=None): - """ - Place an order to adjust a position to a target percent of the + """Place an order to adjust a position to a target percent of the current portfolio value. If the position doesn't already exist, this is equivalent to placing a new order. If the position does exist, this is equivalent to placing an order for the difference between the target percent and the current percent. - Note that target must expressed as a decimal (0.50 means 50\%). + Parameters + ---------- + asset : Asset + The asset that this order is for. + percent : float + The desired percentage of the porfolio value to allocate to + ``asset``. This is specified as a decimal, for example: + 0.50 means 50%. + style : ExecutionStyle + The execution style for the order. + + Returns + ------- + order_id : str + The unique identifier for this order. + + Notes + ----- + ``order_target_value`` does not take into account any open orders. For + example: + + .. code-block:: python + + order_target_percent(sid(0), 10) + order_target_percent(sid(0), 10) + + This code will result in 20% of the portfolio being allocated to sid(0) + because the first call to ``order_target_percent`` will not have been + filled when the second ``order_target_percent`` call is made. + + See Also + -------- + :class:`zipline.finance.execution.ExecutionStyle` + :func:`zipline.api.order` + :func:`zipline.api.order_target` + :func:`zipline.api.order_target_value` """ if not self._can_order_asset(asset): return None @@ -1362,6 +1754,19 @@ class TradingAlgorithm(object): 'get_open_orders. Use `asset` instead.') @api_method def get_open_orders(self, asset=None): + """Retrieve all of the current open orders. + + Parameters + ---------- + asset : Asset + If passed, return only the open orders for the given asset instead + of all open orders. + + Returns + ------- + open_orders : list[Order] + The open orders. + """ if asset is None: return { key: [order.to_api_obj() for order in orders] @@ -1375,11 +1780,31 @@ class TradingAlgorithm(object): @api_method def get_order(self, order_id): + """Lookup an order based on the order id returned from one of the + order functions. + + Parameters + ---------- + order_id : str + The unique identifier for the order. + + Returns + ------- + order : Order + The order object. + """ if order_id in self.blotter.orders: return self.blotter.orders[order_id].to_api_obj() @api_method def cancel_order(self, order_param): + """Cancel an open order. + + Parameters + ---------- + order_param : str or Order + The order_id or order object to cancel. + """ order_id = order_param if isinstance(order_param, zipline.protocol.Order): order_id = order_param.id @@ -1389,6 +1814,8 @@ class TradingAlgorithm(object): @api_method @require_initialized(HistoryInInitialize()) def history(self, bar_count, frequency, field, ffill=True): + """DEPRECATED: use ``data.history`` instead. + """ warnings.warn( "The `history` method is deprecated. Use `data.history` instead.", category=ZiplineDeprecationWarning, @@ -1461,8 +1888,13 @@ class TradingAlgorithm(object): @api_method def set_max_leverage(self, max_leverage=None): - """ - Set a limit on the maximum leverage of the algorithm. + """Set a limit on the maximum leverage of the algorithm. + + Parameters + ---------- + max_leverage : float, optional + The maximum leverage for the algorithm. If not provided there will + be no maximum. """ control = MaxLeverage(max_leverage) self.register_account_control(control) @@ -1484,8 +1916,7 @@ class TradingAlgorithm(object): asset=None, max_shares=None, max_notional=None): - """ - Set a limit on the number of shares and/or dollar value held for the + """Set a limit on the number of shares and/or dollar value held for the given sid. Limits are treated as absolute values and are enforced at the time that the algo attempts to place an order for sid. This means that it's possible to end up with more than the max number of shares @@ -1495,6 +1926,16 @@ class TradingAlgorithm(object): If an algorithm attempts to place an order that would result in increasing the absolute value of shares/dollar value exceeding one of these limits, raise a TradingControlException. + + Parameters + ---------- + asset : Asset, optional + If provided, this sets the guard only on positions in the given + asset. + max_shares : int, optional + The maximum number of shares to hold for an asset. + max_notional : float, optional + The maximum value to hold for an asset. """ control = MaxPositionSize(asset=asset, max_shares=max_shares, @@ -1502,15 +1943,26 @@ class TradingAlgorithm(object): self.register_trading_control(control) @api_method - def set_max_order_size(self, asset=None, max_shares=None, + def set_max_order_size(self, + asset=None, + max_shares=None, max_notional=None): - """ - Set a limit on the number of shares and/or dollar value of any single + """Set a limit on the number of shares and/or dollar value of any single order placed for sid. Limits are treated as absolute values and are enforced at the time that the algo attempts to place an order for sid. If an algorithm attempts to place an order that would result in exceeding one of these limits, raise a TradingControlException. + + Parameters + ---------- + asset : Asset, optional + If provided, this sets the guard only on positions in the given + asset. + max_shares : int, optional + The maximum number of shares that can be ordered at one time. + max_notional : float, optional + The maximum value that can be ordered at one time. """ control = MaxOrderSize(asset=asset, max_shares=max_shares, @@ -1519,25 +1971,33 @@ class TradingAlgorithm(object): @api_method def set_max_order_count(self, max_count): - """ - Set a limit on the number of orders that can be placed within the given - time interval. + """Set a limit on the number of orders that can be placed in a single + day. + + Parameters + ---------- + max_count : int + The maximum number of orders that can be placed on any single day. """ control = MaxOrderCount(max_count) self.register_trading_control(control) @api_method def set_do_not_order_list(self, restricted_list): - """ - Set a restriction on which assets can be ordered. + """Set a restriction on which assets can be ordered. + + Parameters + ---------- + restricted_list : set[Asset] + The assets that cannot be ordered. """ control = RestrictedListOrder(restricted_list) self.register_trading_control(control) @api_method def set_long_only(self): - """ - Set a rule specifying that this algorithm cannot take short positions. + """Set a rule specifying that this algorithm cannot take short + positions. """ self.register_trading_control(LongOnly()) @@ -1547,8 +2007,27 @@ class TradingAlgorithm(object): @api_method @require_not_initialized(AttachPipelineAfterInitialize()) def attach_pipeline(self, pipeline, name, chunksize=None): - """ - Register a pipeline to be computed at the start of each day. + """Register a pipeline to be computed at the start of each day. + + Parameters + ---------- + pipeline : Pipeline + The pipeline to have computed. + name : str + The name of the pipeline. + chunksize : int, optional + The number of days to compute pipeline results for. Increasing + this number will make it longer to get the first results but + may improve the total runtime of the simulation. + + Returns + ------- + pipeline : Pipeline + Returns the pipeline that was attached unchanged. + + See Also + -------- + :func:`zipline.api.pipeline_output` """ if self._pipelines: raise NotImplementedError("Multiple pipelines are not supported.") @@ -1567,8 +2046,8 @@ class TradingAlgorithm(object): @api_method @require_initialized(PipelineOutputDuringInitialize()) def pipeline_output(self, name): - """ - Get the results of pipeline with name `name`. + """Get the results of the pipeline that was attached with the name: + ``name``. Parameters ---------- @@ -1588,6 +2067,7 @@ class TradingAlgorithm(object): See Also -------- + :func:`zipline.api.attach_pipeline` :meth:`zipline.pipeline.engine.PipelineEngine.run_pipeline` """ # NOTE: We don't currently support multiple pipelines, but we plan to diff --git a/zipline/api.py b/zipline/api.py index f88f74e7..ef3a75f8 100644 --- a/zipline/api.py +++ b/zipline/api.py @@ -15,36 +15,33 @@ # Note that part of the API is implemented in TradingAlgorithm as # methods (e.g. order). These are added to this namespace via the -# decorator `api_methods` inside of algorithm.py. - -from .finance import (commission, slippage, cancel_policy) -from .utils import math_utils, events - -from zipline.finance.slippage import ( - FixedSlippage, - VolumeShareSlippage, -) - -from zipline.finance.cancel_policy import ( +# decorator ``api_method`` inside of algorithm.py. +from .finance import commission, execution, slippage, cancel_policy +from .finance.cancel_policy import ( NeverCancel, EODCancel ) - -from zipline.utils.events import ( +from .finance.slippage import ( + FixedSlippage, + VolumeShareSlippage, +) +from .utils import math_utils, events +from .utils.events import ( date_rules, time_rules ) __all__ = [ - 'slippage', - 'commission', - 'cancel_policy', - 'NeverCancel', 'EODCancel', - 'events', - 'math_utils', 'FixedSlippage', + 'NeverCancel', 'VolumeShareSlippage', + 'cancel_policy', + 'commission', 'date_rules', + 'events', + 'execution', + 'math_utils', + 'slippage', 'time_rules' ] diff --git a/zipline/finance/cancel_policy.py b/zipline/finance/cancel_policy.py index bec45764..6a33cd87 100644 --- a/zipline/finance/cancel_policy.py +++ b/zipline/finance/cancel_policy.py @@ -21,16 +21,38 @@ from zipline.gens.sim_engine import DAY_END class CancelPolicy(with_metaclass(abc.ABCMeta)): + """Abstract cancellation policy interface. + """ @abstractmethod def should_cancel(self, event): + """Should all open orders be cancelled? + + Parameters + ---------- + event : enum-value + An event type, one of: + - :data:`zipline.gens.sim_engine.BAR` + - :data:`zipline.gens.sim_engine.DAY_START` + - :data:`zipline.gens.sim_engine.DAY_END` + - :data:`zipline.gens.sim_engine.MINUTE_END` + + Returns + ------- + should_cancel : bool + Should all open orders be cancelled? + """ pass class EODCancel(CancelPolicy): - """ - This policy cancels open orders at the end of the day. For now, Zipline - will only apply this policy to minutely simulations. + """This policy cancels open orders at the end of the day. For now, + Zipline will only apply this policy to minutely simulations. + + Parameters + ---------- + warn_on_cancel : bool, optional + Should a warning be raised if this causes an order to be cancelled? """ def __init__(self, warn_on_cancel=True): self.warn_on_cancel = warn_on_cancel @@ -40,8 +62,7 @@ class EODCancel(CancelPolicy): class NeverCancel(CancelPolicy): - """ - Orders are never automatically canceled. + """Orders are never automatically canceled. """ def __init__(self): self.warn_on_cancel = False diff --git a/zipline/finance/commission.py b/zipline/finance/commission.py index 6618a5bf..e901149f 100644 --- a/zipline/finance/commission.py +++ b/zipline/finance/commission.py @@ -18,9 +18,15 @@ DEFAULT_MINIMUM_COST_PER_TRADE = 1.0 # $1 per trade class PerShare(object): - """ - Calculates a commission for a transaction based on a per + """Calculates a commission for a transaction based on a per share cost with an optional minimum cost per trade. + + Parameters + ---------- + cost : float, optional + The amount of commissions paid per share traded. + min_trade_cost : optional + The minimum amount of commisions paid per trade. """ def __init__(self, @@ -57,9 +63,13 @@ class PerShare(object): class PerTrade(object): - """ - Calculates a commission for a transaction based on a per + """Calculates a commission for a transaction based on a per trade cost. + + Parameters + ---------- + cost : float, optional + The flat amount of commisions paid per trade. """ def __init__(self, cost=DEFAULT_MINIMUM_COST_PER_TRADE): @@ -84,9 +94,13 @@ class PerTrade(object): class PerDollar(object): - """ - Calculates a commission for a transaction based on a per + """Calculates a commission for a transaction based on a per dollar cost. + + Parameters + ---------- + cost : float, optional + The amount of commissions paid per dollar traded. """ def __init__(self, cost=0.0015): diff --git a/zipline/finance/slippage.py b/zipline/finance/slippage.py index e029234f..3c654526 100644 --- a/zipline/finance/slippage.py +++ b/zipline/finance/slippage.py @@ -34,6 +34,8 @@ DEFAULT_VOLUME_SLIPPAGE_BAR_LIMIT = 0.025 class SlippageModel(with_metaclass(abc.ABCMeta)): + """Abstract interface for defining a new slippage model. + """ def __init__(self): self._volume_for_bar = 0 @@ -43,6 +45,24 @@ class SlippageModel(with_metaclass(abc.ABCMeta)): @abc.abstractproperty def process_order(self, data, order): + """Process how orders get filled. + + Parameters + ---------- + data : BarData + The data for the given bar. + order : Order + The order to simulate. + + Returns + ------- + execution_price : float + The price to execute the trade at. + execution_volume : int + The number of shares that could be filled. This may not be all + the shares ordered in which case the order will be filled over + multiple bars. + """ pass def simulate(self, data, asset, orders_for_asset): @@ -91,6 +111,8 @@ class SlippageModel(with_metaclass(abc.ABCMeta)): class VolumeShareSlippage(SlippageModel): + """Model slippage as a function of the volume of shares traded. + """ def __init__(self, volume_limit=DEFAULT_VOLUME_SLIPPAGE_BAR_LIMIT, price_impact=0.1): @@ -162,13 +184,15 @@ class VolumeShareSlippage(SlippageModel): class FixedSlippage(SlippageModel): + """Model slippage as a fixed spread. + + Parameters + ---------- + spread : float, optional + spread / 2 will be added to buys and subtracted from sells. + """ def __init__(self, spread=0.0): - """ - Use the fixed slippage model, which will just add/subtract - a specified spread spread/2 will be added on buys and subtracted - on sells per share - """ self.spread = spread def process_order(self, data, order): diff --git a/zipline/sources/requests_csv.py b/zipline/sources/requests_csv.py index c71ee96b..a505c271 100644 --- a/zipline/sources/requests_csv.py +++ b/zipline/sources/requests_csv.py @@ -1,15 +1,16 @@ -from six import StringIO, iteritems from abc import ABCMeta, abstractmethod from collections import namedtuple import hashlib from textwrap import dedent +import warnings + +from logbook import Logger +import numpy import pandas as pd from pandas import read_csv -import numpy -from logbook import Logger import pytz -import warnings import requests +from six import StringIO, iteritems, with_metaclass from zipline.errors import ( MultipleSymbolsFound, @@ -138,8 +139,7 @@ def mask_requests_args(url, validating=False, params_checker=None, **kwargs): return request_pair(requests_kwargs, url) -class PandasCSV(object): - __metaclass__ = ABCMeta +class PandasCSV(with_metaclass(ABCMeta, object)): def __init__(self, pre_func, diff --git a/zipline/utils/events.py b/zipline/utils/events.py index a5e3a81c..8875159f 100644 --- a/zipline/utils/events.py +++ b/zipline/utils/events.py @@ -42,8 +42,6 @@ __all__ = [ 'OncePerDay', # Factory API - 'DateRuleFactory', - 'TimeRuleFactory', 'date_rules', 'time_rules', 'make_eventrule', @@ -668,7 +666,7 @@ class OncePerDay(StatefulRule): # Factory API -class DateRuleFactory(object): +class date_rules(object): every_day = Always @staticmethod @@ -688,16 +686,11 @@ class DateRuleFactory(object): return NDaysBeforeLastTradingDayOfWeek(n=days_offset) -class TimeRuleFactory(object): +class time_rules(object): market_open = AfterOpen market_close = BeforeClose -# Convenience aliases. -date_rules = DateRuleFactory -time_rules = TimeRuleFactory - - def make_eventrule(date_rule, time_rule, half_days=True): """ Constructs an event rule from the factory api.