Coder Social home page Coder Social logo

bankroll-py / bankroll Goto Github PK

View Code? Open in Web Editor NEW
60.0 10.0 6.0 510 KB

Ingest portfolio and other data from multiple brokerages, and analyze it

License: MIT License

Jupyter Notebook 18.60% Python 81.40%
python python3 cli finance portfolio jupyter-notebook trading investment

bankroll's Introduction

bankroll PyPI version CircleCI

Command line interface and notebook utilities to ingest portfolio and other data from multiple brokerages, and analyze it.

This is the frontend to the bankroll project, which is comprised of several libraries that can also be used on their own.

Table of contents:

  1. Installation
  2. Connecting to brokers
    1. Interactive Brokers
    2. Charles Schwab
    3. Fidelity
    4. Vanguard
    5. (your broker here)
  3. Saving configuration
  4. Extending bankroll

Installation

To install the bankroll command line utility, select from the list of available brokerage plugins, and run pip install with those brokerages listed as extras.

For example, to install bankroll with support for Interactive Brokers and Charles Schwab:

pip3 install bankroll[ibkr,schwab]

Or from the repository root, if you have cloned the code:

pip3 install .[ibkr,schwab,fidelity]

Once installed (and presuming your Python path is set up correctly), the command line tool can be invoked directly:

bankroll --help

Connecting to brokers

After being set up, bankroll can be used from the command line to bring together data from multiple brokerages.

For example, to show all positions held in both Interactive Brokers and Charles Schwab:

bankroll \
  --ibkr-tws-port 7496 \
  --schwab-positions ~/Positions-2019-01-01.CSV \
  --schwab-transactions ~/Transactions_20190101.CSV \
  positions

Run with --help to see all options:

bankroll --help

Interactive Brokers

Interactive Brokers (sometimes abbreviated as IB or IBKR) offers a well-supported API, which—along with ib_insync—makes it possible to load up-to-date portfolio data and request real-time information about particular securities.

For bankroll, this functionality is implemented via the bankroll-broker-ibkr plugin:

pip3 install bankroll[ibkr]

To load data from Interactive Brokers, one of IB's trading applications—Trader Workstation or IB Gateway—must be running and logged-in to accept API connections. You may wish to use IBC to automate the startup and login of these applications.

Once Trader Workstation or IB Gateway is running, and API connections are enabled, provide the local port number to bankroll like so:

bankroll \
  --ibkr-tws-port 7496 \
  [command]

Querying trade history

IB's Trader Workstation API does not support retrieving information about an account's historical trades, so bankroll must use their Flex Web Service.

To set this up, log in to Account Management, then browse to SettingsAccount Settings in the sidebar:

Account Settings

In the Reporting section of this page, click the gear to configure Flex Web Service:

Flex Web Service

Once configured, copy the Current Token for use on the command line.

Then, you must save a query for bankroll to use. Back in the sidebar, browse to ReportsFlex Queries:

Flex Queries

Click the gear to configure Custom Flex Queries:

Custom Flex Queries

Create a new Trade Confirmation Flex Query Template:

Trade Confirmation Flex Query Templates

Pick a name of your choosing, then make sure the Date Period reflects the historical period you care about (e.g., Last 365 Calendar Days):

Trade Confirmation Flex Query Details

Under Sections, click Trade Confirmations and enable everything in the dialog which appears:

Trade Confirmation button

Trade Confirmation options

After saving your query, expand it in the list to view and copy the Query ID for use on the command line.

With the token and the query ID from your account, historical trades can be downloaded:

bankroll \
  --ibkr-flex-token [token] \
  --ibkr-trades [query ID] \
  activity

Querying dividend history

This workflow will be simplified in the future.

To incorporate the history of dividend payments in your portfolio, follow the same steps for the Trade Confirmation Flex Query, but create an Activity Flex Query instead.

The only section which needs to be enabled is Change in Dividend Accruals:

Activity query options

Pass your existing token, and the new query's ID, on the command line:

bankroll \
  --ibkr-flex-token [token] \
  --ibkr-activity [query ID] \
  activity

Charles Schwab

Charles Schwab does not offer an API, but it does provide CSV files for export, which bankroll can then import.

This functionality is implemented via the bankroll-broker-schwab plugin:

pip3 install bankroll[schwab]

Browse to the "Positions" and/or "Transactions" screen:

Positions and Transactions

Click the "Export" link in the top-right:

Export

Then provide the paths of either or both these downloaded files to bankroll:

bankroll \
  --schwab-positions ~/path/to/Positions.CSV \
  --schwab-transactions ~/path/to/Transactions.CSV \
  [command]

Fidelity

Fidelity is supported through a similar facility as Schwab.

This functionality is implemented via the bankroll-broker-fidelity plugin:

pip3 install bankroll[fidelity]

More detailed instructions have yet to be written—contributions welcome!

Vanguard

Vanguard is a work in progress, and may not be as fully-featured as the other brokerages listed here. Support is being developed in the bankroll-broker-vanguard plugin:

(your broker here)

bankroll intends to abstract away broker-specific details as much as possible, to minimize the work required to support each one, so if your broker isn't listed above, please consider building a new brokerage plugin! We want the list to grow over time, because it's extremely useful to be able to aggregate and analyze data across multiple brokers at once.

To add a new brokerage, create a new subclass of AccountData, then implement the methods as required by the interface. As long as the new subclass is loaded at runtime, it will be automatically included in functionality like data aggregation.

If the brokerage offers a facility to load market data, consider extending the bankroll-marketdata interfaces as well (though this is optional).

Saving configuration

To preserve settings across runs, all of the command-line arguments demonstrated above can also be saved into an INI file. The configuration file is especially useful to store default values, because when a setting is specified in a configuration file as well as on the command line, the command-line argument will take precedence.

To create a configuration, copy bankroll.default.ini to ~/.bankroll.ini, or leave it in your working directory as bankroll.ini, then edit the file to apply your desired settings.

If you would like to store the configuration somewhere else, you can also provide custom paths via the --config argument on the command line.

Extending bankroll

Although the command-line interface exposes a basic set of functionality, it will never be able to capture the full set of possible use cases. For much greater flexibility, you can write Python code to use bankroll directly, and build on top of its APIs for your own purposes.

For some examples, see the included notebooks.

bankroll's People

Contributors

joshvera avatar jspahrsummers avatar kastiglione avatar shadoflamex avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

bankroll's Issues

Support cash positions

Knowing how much "spare" cash is lying about would be handy for rebalancing, for example.

Record dividend payments

Not just trades. This should probably involve refactoring Trade into a hierarchy of classes, and getting rid of TradeFlags entirely.

Make ibapi and ib_insync optional

This will require carefully conditionalizing all imports of ib_insync, as even just touching it will check that ibapi is installed.

This would make bankroll less useful today, but once we have alternative data sources (e.g., #32), it could make getting started much easier.

Figure out underlying for futures contracts

e.g., ES might say something like SPX, while single-stock futures will naturally use the underlying stock. This may be relevant for calculating the realizedBasis of a security.

UnboundLocalError on clean install

Without any settings established or command-line arguments, this error occurs:

> python -m bankroll positions
  File "bankroll\brokers\ibkr.py", line 842, in fromSettings
    trades=trades,
UnboundLocalError: local variable 'trades' referenced before assignment

IB GBP positions multiplied incorrectly

Securities denominated in GBP (pound sterling) are often actually denominated in GBX (pence sterling), and the reporting of this through IB's API is unclear. Currently we're showing GBX values as GBP, grossly overinflating the actual value.

Automatically add CLI settings from defined Settings classes

If Settings enums could be defined with enough context to present meaningful CLI information, we could use Settings.__subclasses__() to get rid of the manual argument generation in __main__.py, which would simplify the code and make extension easier.

Calculate lots from transaction log

There should be enough information in a (complete) transaction log to reconstruct which lots were bought and sold when, which may be useful for tax or other purposes.

EV calculations somehow?

It will be hard to calculate a "true" Expected Value because we don't know how often a particular strategy "should" win (simulations will not be accurate if some strategies are premised on news events or market psychology), but perhaps we could draw conclusions about how often a particular shape of strategy has worked for the user, then feed in the win/lose amounts to determine a sort of historical EV.

Standardized, lazy brokerage data loading

It'd be nice to populate some kind of "broker loader" with the right settings to find whatever data it needs (an IB connection, for example, or file paths for other brokers), and then allow consumers to lazily consume information like positions, activity, etc.—effectively standardizing the read interface for all broker modules.

This might also decouple DataAggregator from some of the implementation details, which would be nice.

Batch live data fetching

APIs like IB's will likely be faster to fetch data for a bunch of contracts at once, as opposed to one-by-one.

Generative tests for data received from IB API

IB's Python API is not well-typed or well-documented, so there will likely be tons of corner cases in our parsing code. We should have a set of fuzz tests that yield complete crap, just to make sure that our parsing will handle whatever gets thrown at it. (We can use hypothesis for this, like our property-based tests.)

"Downloading report" spinner only spins with --verbose

e.g., with --verbose enabled:

Downloading Activity report |INFO:ib_insync.flexreport:still working...
Downloading Activity report /INFO:ib_insync.flexreport:still working...
Downloading Activity report -INFO:ib_insync.flexreport:still working...
Downloading Activity report \INFO:ib_insync.flexreport:still working...
Downloading Activity report |INFO:ib_insync.flexreport:still working...
Downloading Activity report /INFO:ib_insync.flexreport:still working...
Downloading Activity report -INFO:ib_insync.flexreport:still working...
Downloading Activity report \INFO:ib_insync.flexreport:still working...
Downloading Activity report |INFO:ib_insync.flexreport:still working...
Downloading Activity report /INFO:ib_insync.flexreport:still working...
Downloading Activity report -INFO:ib_insync.flexreport:still working...
Downloading Activity report \INFO:ib_insync.flexreport:still working...
Downloading Activity report |INFO:ib_insync.flexreport:still working...
Downloading Activity report /INFO:ib_insync.flexreport:still working...
Downloading Activity report -INFO:ib_insync.flexreport:still working...
Downloading Activity report \INFO:ib_insync.flexreport:still working...
Downloading Activity report |INFO:ib_insync.flexreport:still working...
Downloading Activity report /INFO:ib_insync.flexreport:still working...
Downloading Activity report -INFO:ib_insync.flexreport:still working...
Downloading Activity report \INFO:ib_insync.flexreport:still working...
Downloading Activity report |INFO:ib_insync.flexreport:still working...
Downloading Activity report /INFO:ib_insync.flexreport:still working...

If it's not enabled this way, the spinner hangs for quite a while.

IB options' cost basis getting lost

Options aren't printing their cost basis even when the underlying is. Inspection of debug logging shows that IB is correctly returning an average price for the options, so not sure what's going on.

Country exposure

Calculate total exposure to countries (or maybe regions, generally) based on positions and cash held.

ValueError(f"Unexpected type of activity: {activity}")

I get this error when attempting to run bankroll (even simple --help) after install in a fresh conda virtual environment (python 3.6).

$ bankroll --help
Traceback (most recent call last):
File "c:\users\lee\anaconda3\envs\foliolyze\lib\runpy.py", line 193, in run_module_as_main
"main", mod_spec)
File "c:\users\lee\anaconda3\envs\foliolyze\lib\runpy.py", line 85, in run_code
exec(code, run_globals)
File "C:\Users\lee\Anaconda3\envs\foliolyze\Scripts\bankroll.exe_main
.py", line 5, in
File "c:\users\lee\anaconda3\envs\foliolyze\lib\site-packages\bankroll\interface_init
.py", line 1, in
from bankroll.analysis import *
File "c:\users\lee\anaconda3\envs\foliolyze\lib\site-packages\bankroll\analysis_init_.py", line 1, in
from .analysis import (
File "c:\users\lee\anaconda3\envs\foliolyze\lib\site-packages\bankroll\analysis\analysis.py", line 88
raise ValueError(f"Unexpected type of activity: {activity}")

@dataclass all the things

We've implemented a bunch of really basic operations like __repr__ and __eq__ in our models. Let's use the @dataclass decorator as much as possible instead.

Split up project into separate components + responsibilities

In trying to build another project which wants to use pieces of bankroll, I'm finding the current structure kind of unwieldy, and don't want to risk this becoming a kitchen sink. At bare minimum, we should probably separate the model from the brokerage support from the analysis and tools.

Something like this, although not necessarily as finely-sliced:

component graph

digraph {
  rankdir = BT;
  { rank = min; model; }
  { rank = same; ibkr; schwab; fidelity; vanguard; }
  { rank = same; analysis, "plugin framework" }
  { rank = max; cli, notebooks }
  ibkr, schwab, fidelity, vanguard -> model
  ibkr, schwab, fidelity, vanguard -> "plugin framework" [style=dashed]
  analysis -> model
  notebooks -> analysis, "plugin framework"
  cli -> analysis, "plugin framework"
}

Plugin architecture?

I was thinking that it might be useful to support a concept of plugins, in the form of (at least) additional verbs for the command-line, similarly to other CLI tools.

A motivating example could be: a separate project which adds a bankroll command for offline storage and syncing of activity logs.

Trade journal support

I think I've come up with a structured format that should work as a reusable trade journal, which could conveniently be joined/informed by bankroll activity logs. Assigning to myself to work out the details.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.