Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Select Account id when using Single Sign-On (SSO) in live trading #104

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
3 changes: 3 additions & 0 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import sys
import os
currDir = os.path.dirname(os.path.realpath(__file__))
rootDir = os.path.abspath(os.path.join(currDir, '../..'))
sys.path.append(rootDir)

from zipline import __version__ as version

Expand Down
219 changes: 219 additions & 0 deletions docs/source/development-guidelines.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
Development Guidelines
======================
This page is intended for developers of Zipline-Live, people who want to contribute to the Zipline-Live codebase or documentation, or people who want to install from source and make local changes to their copy of Zipline-Live.

All contributions, bug reports, bug fixes, documentation improvements, enhancements and ideas are welcome. We `track issues`__ on `GitHub`__ and also have a `mailing list`__ where you can ask questions.

__ https://github.com/zipline-live/zipline/issues
__ https://zipline-live.slack.com/
__ https://groups.google.com/forum/#!forum/zipline-live

Zipline-Live is built upon Zipline tha tis accessible at

__ https://github.com/quantopian/zipline

Creating a Development Environment
----------------------------------

First, you'll need to clone Zipline by running:

.. code-block:: bash

$ git clone git@github.com:zipline-live/zipline.git

Then check out to a new branch where you can make your changes:

.. code-block:: bash

$ git checkout -b some-short-descriptive-name

If you don't already have them, you'll need some C library dependencies. You can follow the `install guide`__ to get the appropriate dependencies.

__ install.html

The following section assumes you already have virtualenvwrapper and pip installed on your system. Suggested installation of Python library dependencies used for development:

.. code-block:: bash

$ mkvirtualenv zipline
$ ./etc/ordered_pip.sh ./etc/requirements.txt
$ pip install -r ./etc/requirements_dev.txt
$ pip install -r ./etc/requirements_blaze.txt
$ pip install -r ./etc/requirements_ib.txt

Finally, you can build the C extensions by running:

.. code-block:: bash

$ python setup.py build_ext --inplace

To finish, make sure `tests`__ pass.

__ #style-guide-running-tests

If you get an error running nosetests after setting up a fresh virtualenv, please try running

.. code-block:: bash

# where zipline is the name of your virtualenv
$ deactivate zipline
$ workon zipline


Development with Docker
-----------------------

If you want to work with zipline using a `Docker`__ container, you'll need to build the ``Dockerfile`` in the Zipline root directory, and then build ``Dockerfile-dev``. Instructions for building both containers can be found in ``Dockerfile`` and ``Dockerfile-dev``, respectively.

__ https://docs.docker.com/get-started/


Style Guide & Running Tests
---------------------------

We use `flake8`__ for checking style requirements and `nosetests`__ to run Zipline tests. Our `continuous integration`__ tools will run these commands.

__ http://flake8.pycqa.org/en/latest/
__ http://nose.readthedocs.io/en/latest/
__ https://en.wikipedia.org/wiki/Continuous_integration

Before submitting patches or pull requests, please ensure that your changes pass when running:

.. code-block:: bash

$ flake8 zipline tests

In order to run tests locally, you'll need `TA-lib`__, which you can install on Linux by running:

__ https://mrjbq7.github.io/ta-lib/install.html

.. code-block:: bash

$ wget http://prdownloads.sourceforge.net/ta-lib/ta-lib-0.4.0-src.tar.gz
$ tar -xvzf ta-lib-0.4.0-src.tar.gz
$ cd ta-lib/
$ ./configure --prefix=/usr
$ make
$ sudo make install

And for ``TA-lib`` on OS X you can just run:

.. code-block:: bash

$ brew install ta-lib

Then run ``pip install`` TA-lib:

.. code-block:: bash

$ pip install -r ./etc/requirements_talib.txt

You should now be free to run tests:

.. code-block:: bash

$ nosetests


Continuous Integration
----------------------

We use `Travis CI`__ for Linux-64 bit builds and `AppVeyor`__ for Windows-64 bit builds.

.. note::

We do not currently have CI for OSX-64 bit builds. 32-bit builds may work but are not included in our integration tests.

__ https://travis-ci.org/quantopian/zipline
__ https://ci.appveyor.com/project/quantopian/zipline


Packaging
---------
To learn about how we build Zipline conda packages, you can read `this`__ section in our release process notes.

__ release-process.html#uploading-conda-packages

Contributing to the Docs
------------------------

If you'd like to contribute to the documentation on zipline.io, you can navigate to ``docs/source/`` where each `reStructuredText`__ (``.rst``) file is a separate section there. To add a section, create a new file called ``some-descriptive-name.rst`` and add ``some-descriptive-name`` to ``appendix.rst``. To edit a section, simply open up one of the existing files, make your changes, and save them.

__ https://en.wikipedia.org/wiki/ReStructuredText

We use `Sphinx`__ to generate documentation for Zipline, which you will need to install by running:

__ http://www.sphinx-doc.org/en/stable/


.. code-block:: bash

$ pip install -r ./etc/requirements_docs.txt

To build and view the docs locally, run:

.. code-block:: bash

# assuming you're in the Zipline root directory
$ make -C ./docs/ html
$ {BROWSER} build/html/index.html


Commit messages
---------------

Standard prefixes to start a commit message:

.. code-block:: text

BLD: change related to building Zipline
BUG: bug fix
DEP: deprecate something, or remove a deprecated object
DEV: development tool or utility
DOC: documentation
ENH: enhancement
MAINT: maintenance commit (refactoring, typos, etc)
REV: revert an earlier commit
STY: style fix (whitespace, PEP8, flake8, etc)
TST: addition or modification of tests
REL: related to releasing Zipline
PERF: performance enhancements


Some commit style guidelines:

Commit lines should be no longer than `72 characters`__. The first line of the commit should include one of the above prefixes. There should be an empty line between the commit subject and the body of the commit. In general, the message should be in the imperative tense. Best practice is to include not only what the change is, but why the change was made.

__ https://git-scm.com/book/en/v2/Distributed-Git-Contributing-to-a-Project

**Example:**

.. code-block:: text

MAINT: Remove unused calculations of max_leverage, et al.

In the performance period the max_leverage, max_capital_used,
cumulative_capital_used were calculated but not used.

At least one of those calculations, max_leverage, was causing a
divide by zero error.

Instead of papering over that error, the entire calculation was
a bit suspect so removing, with possibility of adding it back in
later with handling the case (or raising appropriate errors) when
the algorithm has little cash on hand.


Formatting Docstrings
---------------------

When adding or editing docstrings for classes, functions, etc, we use `numpy`__ as the canonical reference.

__ https://github.com/numpy/numpy/blob/master/doc/HOWTO_DOCUMENT.rst.txt


Updating the Whatsnew
---------------------

We have a set of `whatsnew <https://github.com/quantopian/zipline/tree/master/docs/source/whatsnew>`__ files that are used for documenting changes that have occurred between different versions of Zipline.
Once you've made a change to Zipline, in your Pull Request, please update the most recent ``whatsnew`` file with a comment about what you changed. You can find examples in previous ``whatsnew`` files.
14 changes: 13 additions & 1 deletion zipline/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,12 @@ def _(*args, **kwargs):
show_default=True,
help='Connection to broker',
)
@click.option(
'--account-id',
default='',
metavar='ACT-ID',
help='Account ID to trade on from a single sign-on (SSO) for consolidated/individual or linked/advisor accounts',
)
@click.option(
'--state-file',
default=None,
Expand Down Expand Up @@ -234,6 +240,7 @@ def run(ctx,
local_namespace,
broker,
broker_uri,
account_id,
state_file,
realtime_bar_target,
list_brokers):
Expand Down Expand Up @@ -284,7 +291,11 @@ def run(ctx,
except AttributeError:
ctx.fail("unsupported broker: can't import class %s from %s" %
(cl_name, mod_name))
brokerobj = bclass(broker_uri)

if account_id is '':
brokerobj = bclass(broker_uri)
else:
brokerobj = bclass(broker_uri, account_id)

if (algotext is not None) == (algofile is not None):
ctx.fail(
Expand Down Expand Up @@ -312,6 +323,7 @@ def run(ctx,
local_namespace=local_namespace,
environ=os.environ,
broker=brokerobj,
account_id=account_id,
state_filename=state_file,
realtime_bar_target=realtime_bar_target
)
Expand Down
6 changes: 6 additions & 0 deletions zipline/algorithm_live.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,19 @@ def __init__(self, *args, **kwargs):
class LiveTradingAlgorithm(TradingAlgorithm):
def __init__(self, *args, **kwargs):
self.broker = kwargs.pop('broker', None)

# todo(flo) this might be unnecessary - validate in the future (refer to IBBroker)
self.account_id = kwargs.pop('account_id', None)
self.orders = {}

self.algo_filename = kwargs.get('algo_filename', "<algorithm>")
self.state_filename = kwargs.pop('state_filename', None)
self.realtime_bar_target = kwargs.pop('realtime_bar_target', None)
self._context_persistence_excludes = []

if self.account_id is not '':
self.broker.set_account_id(self.account_id)

if 'blotter' not in kwargs:
blotter_live = BlotterLive(
data_frequency=kwargs['sim_params'].data_frequency,
Expand Down
19 changes: 17 additions & 2 deletions zipline/gens/brokers/ib_broker.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@ def connect(self):

self._download_account_details()
log.info("Managed accounts: {}".format(self.managed_accounts))
if len(self.managed_accounts) > 1:
log.info("Multiple linked accounts are detected. You will need to specify one Account to trade on")

self.reqCurrentTime()
self.reqIds(1)
Expand All @@ -149,6 +151,7 @@ def _download_account_details(self):
while self.managed_accounts is None:
sleep(_poll_frequency)

self.managed_accounts = [nonempty for nonempty in self.managed_accounts if nonempty]
for account in self.managed_accounts:
self.reqAccountUpdates(subscribe=True, acctCode=account)
while self.accounts_download_complete is False:
Expand Down Expand Up @@ -486,14 +489,26 @@ def __init__(self, tws_uri, account_id=None):
self._transactions = {}

self._tws = TWSConnection(tws_uri)
self.account_id = (self._tws.managed_accounts[0] if account_id is None
else account_id)

if account_id is None and len(self._tws.managed_accounts) == 1:
self.account_id = self._tws.managed_accounts[0]
elif account_id is None:
log.error("Multiple linked-accounts detected for Single Sign-On, BUT no account ID as been specified")
self._tws.close()
else:
self.set_account_id(account_id)

self.currency = 'USD'

self._subscribed_assets = []

super(self.__class__, self).__init__()

def set_account_id (self, accountid):
self.account_id = accountid
self._tws.reqAccountUpdates (subscribe=True, acctCode=self.account_id)
log.info("Updating Linked Account to : {}".format(self.account_id))

@property
def subscribed_assets(self):
return self._subscribed_assets
Expand Down
2 changes: 2 additions & 0 deletions zipline/utils/run_algo.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ def _run(handle_data,
local_namespace,
environ,
broker,
account_id,
state_filename,
realtime_bar_target):
"""Run a backtest for the given algorithm.
Expand Down Expand Up @@ -177,6 +178,7 @@ def choose_loader(column):

TradingAlgorithmClass = (partial(LiveTradingAlgorithm,
broker=broker,
account_id=account_id,
state_filename=state_filename,
realtime_bar_target=realtime_bar_target)
if broker else TradingAlgorithm)
Expand Down