The initialization of perf_tracker had been moved from __init__
in TradingAlgorithm to _create_generator. This caused perf_tracker
to not be ready when portfolio requested it. portfolio was consequently
not ready for access in init. portfolio can now be accessed in init
again, assuming valid sim_params are passed. Otherwise it will be
available in handle_data() after _create_generator() is called.
Removes support for handling dividends as part of the algorithm
simulation stream, replacing it with an API in `TradingAlgorithm` for
supplying dividends as a DataFrame.
Breaks out the main snapshot processing loop into its own function, and does
some minor variable renaming-shuffling.
Adds `TradingAlgorithm.on_dt_changed`, a function to be called when the
simulation dt changes, prior to processing any events.
There should be no difference in behavior as a result of this change.
Created a new flag in TradingAlgorithm that enables subclasses to
decide if they want to handle setting self.initialized = True.
Before it was the responsibility of an overriding subclass to set
initalized = True. This was causing problems because it's easy to
forget this. Now it is the responsibility of TradingAlgorithm
unless explicity stated otherwise.
Previously, calling order() in initalize resulted in a weird
stack trace. It now returns a well formulated error that is
readable to the user through the API. Adding a slippage
kwarg to test_algorithm and simfactor was necessary because
slippage can only be called during init. Previously initaliazed
was never set to true and calls to init-only function were sprinkled
around the code in non-init sections. Code changes were to enforce
init-only rules.
There were sevaral places you could supply sim_params
in TradingAlgorithm (__init__, run). This got confusing
as its not clear who updated what and which one was the
correct one to use at each time.
Then there were to ways to define data_frequency, one in
__init__() and one in the sim_params which also added code
complexity.
This refactor makes it explicit that sim_params are to be
passed to __init__() only. Moreover, data_frequency is
only stored in sim_params. For backwards compatibility,
it can still be supplied separately but will link to
the one in sim_params.
For example, you could create new sim params via:
sim_params = create_simulation_parameters(data_frequency='minute')
algo = MyAlgo(sim_params)
algo.run(data)
In addition, perf_tracker only gets initialized in one place:
_create_generator() which should also make the various ways
of running an algorithm more deterministic.
This also fixes a bug with SimulationParameters where
you could not change the period_start. Unfortunately, the
current implementation still requieres an implicit call to
update the internal variables.
Truncate non-integer order amounts in `TradingAlgorithm.order` instead of
`Blotter.order`. This fixes an issue where non-integer orders coming out of
order_value can spuriously trigger a `LongOnly` trading guard.
Example:
sid.price == 2.0
order_value(sid, 5) -> order(sid, 2.5) -> truncated to order(sid, 2.0)
order_value(sid, -5) -> order(sid, -2.5) -> LongOnlyViolation b/c 2.0 - 2.5 < 0
Refactored the target order methods to separate their logic from the
other order methods.
This makes order_target the only target method that calls order()
directly.
order_target_value is passed to order_target instead of order_value.
order_target_percent is passed to order_target_value rather than
order_value.
This simplified the code and decouples the logic of target orders from
the other order methods. This allows the target order methods to be
developed independently from order_value and order_percent.
Filter out empty lists from `get_open_orders` so that we have consistent
behavior between the case where a user has never placed an order and the case
where the user has placed an order but it has been executed or cancelled.
A nice side-effect, which was the impetus for this change, is that you can
check if you have any open orders by doing:
```
len(get_open_orders()) == 0
```
Also adds a test for the behavior of `get_open_orders`, which was previously
lacking.
Make the portfolio property on TradingAlgorithm call `updated_portfolio`
internally. This prevents needless recomputation of the portfolio between
calls to `handle_data`, and also prevents issues where the portfolio object
could be unexpectedly modified in place in the body of a `handle_data` call.
Noteworthy finding in the course of investigating this bug:
If you modify a Python dictionary while iterating over it, the language will
only throw an exception if the size of the dictionary changes between loop
iterations; this means that you can do:
```
x = {1:1, 2:2, 3:3}
for k in x:
old_val = x[k]
del x[k]
x[f(k)] = old_val
print k
```
and you'll only get an error if f(k) is already a key in the dictionary.
This can lead to bizarre/nondeterministic behavior in the key iterator.
Adds four new methods to the Zipline API that can be used as circuit-breakers
to interrupt the execution of an algorithm. The API methods are:
`set_max_position_size`
`set_max_order_size`
`set_max_order_count`
`set_long_only`
Internally, these methods are implemented by each registering a TradingControl
callback object with the TradingAlgorithm. During
TradingAlgorithm.__validate_order_params (and thus before any side-effects of
the order call occur), each callback's `validate` method is called with
information about the order to be placed and the algorithm's current state,
raising an exception if the callback detects that an error condition has been breached.
When zipline is imported it checks whether
it runs in the IPython notebook. If it does,
it registers a %%zipline magic that takes the
same arguments as the CLI with the addition of
a -o for specifying the output variable to store
the performance frame in.
The algo code in the cell is, as of yet, executed
in its own environment rather than that of the
IPython NB which is probably what we want.
Also adds cli option to save the perf dataframe
to a pickle file.
Also adds an IPython notebook buyapple example.
Add a CLI that reads in an algorithm, loads data,
run the algorithm, and output performance metrics.
The examples are adapted to the new zipline API and
analyses are split into separate files.
Also add config files that run the example
algorithms with preset settings.
Add `style` parameter to order_value, order_percent, order_target,
order_target_percent, and order_target_value methods. The style parameter is
forwarded to the underlying call to `order`.
existing `limit_price` and `stop_price` parameters. The goal of this change is
to refactor the existing ordering API to provide a cleaner interface for
defining more complex order types.
Adds a new module, zipline.finance.execution, which defines the ExecutionStyle
abstract base class, along with concrete MarketOrder, LimitOrder, StopOrder,
and StopLimitOrder subclasses.
Adds a new `style` keyword argument to the function signature of the `order`
API method, which accepts an instance of ExecutionStyle.
The existing limit_price and stop_price parameters are still supported at this
time, but are converted into the new ExecutionStyle objects before being passed
to Blotter.order.
TradingAlgorithm always uses set_algo_instance in pairs of
set_algo_instance(self) and set_algo_instance(None). Refactoring this to use a
context manager.
It seems more clear to get price values from
`self.trading_client.current_data[sid].price` than
from `self.portfolio.positions[sid].last_sale_price`.
The two values are the same, so this is just a readability change,
but it is also the same behavior as in `self.order_value()` and it's
good to have them all be the same.
Adding a copy of the Event's dt field as datetime via the
`alias_dt` generator, so that the API was forgiving and allowed
both datetime and dt on a SIDData object, was creating noticeable
overhead, even on an noop algorithms.
Instead of incurring the cost of copying the datetime value and
assigning it to the Event object on every event that is passed
through the system, add a property to SIDData which acts as an
alias `datetime` to `dt`.
Eventually support for `data['foo'].datetime` may be removed,
and could be considered deprecated.
Though defining the `initialize` method may end up being explicitly
required, in the meantime prevent existing algorithms from crashing
by providing a noop function when `initialize` is not defined.
For compatibility with existing behavior of having the,
data_frequency of the algorithm override the simulation parameters.
We may want to consider throwing an exception if the two do not match.
In the case that data_frequency of the algorithm is None,
allow the sim_params to provide the data_frequency.
For less redundancy when setting up an algorithm.
When running with minutely emissions the simulator would report to the
user that it simulated 'n - 1' days (where n is the number of days
specified in the simulation params). Now the correct number of trading
days are reported as being simulated.
Previously benchmark events were emitted at 0:00 on the day the
benchmark related to: in 'minute' emission mode this meant that
the benchmarks were emitted before any intra-day trades were
processed.
See: https://github.com/quantopian/zipline/issues/241
This is a step towards the goal of uniting Quantopian scripts
and zipline.
To make the syntax of zipline identical to Quantopian
we break out the API methods (like order) and turn them into
functions. To access the algo object we add a thread local reference
to the current algorithm that is accessed in the API functions.
TradingAlgorithm now takes either a string or two functions
(initialize and handle_data) that it executes.
Use api method decorator for methods available in algoscript.
Ported appropriate algorithm tests from internal code.
Use the six module to import functions and types that are
consistent between Python 2 and 3, so that one code base can
support both versions.
- Use integer types instead of int and long.
- Use string_types instead of basestring.
- Account for iteritems, itervalues, iterkeys.
- Use six.moves for filter and zip, reduce
- Use compatible bytes for md5 hasher.
- xrange and range
So that each reference to `.portfolio` in the algoscript,
cache the value of the portfolio, and mark the need for a new
value at the end of each dt in the tradesimulation loop.
Remove the lists of DailyReturn objects in favor of using pd.Series
to store the return values.
Should make it easier to inspect the values when stepping through,
make the windowing of data to a certain range more facile by using,
and have some performance increases due to removing object creation
and member access.