项目作者: philipodonnell

项目描述 :
An open source simulated options brokerage and UI for paper trading, algorithmic interfaces and backtesting.
高级语言: Python
项目地址: git://github.com/philipodonnell/paperbroker.git
创建时间: 2017-07-06T02:04:51Z
项目社区:https://github.com/philipodonnell/paperbroker

开源协议:MIT License

下载


paperbroker

A python3 open source simulated brokerage for paper trading, algorithms and backtesting. Trade stocks, bonds, options and many other securities via adapters.

  1. To use the package:
  2. pip install git+https://github.com/philipodonnell#egg=paperbroker
  3. from paperbroker import PaperBroker
  4. broker=PaperBroker()
  5. or to use the HTTP REST/JSON API and/or the UI interface:
  6. git clone https://github.com/philipodonnell/paperbroker
  7. install dependencies and execute with python server.py.
  8. navigate your browser to http://localhost:8231/

Features

When I was learning to trade options I needed a free API-driven broker simulation that understood options so that I could paper trade my strategies. I built paperbroker to meet that need and I hope it will help you too.

  • Specialized classes for different kinds of assets (including option greeks)
  • Brokerage business logic in dedicated modules
  • Automatically handles option expirations
  • Interchangable, extensible, transaction pricing estimators
  • 4 days of real option pricing data included for development and testing
  • Optional Flask-based HTTP REST/JSON server

Contributors and contributions are welcome! My hope is that this codebase will grow beyond my original use case to help many more people learn about options trading and investment. More is coming very soon, including:

  • Margins on naked calls and puts (help!)
  • Commission handling
  • Additional data sources
  • Built-in paper trading UI
  • Free hosted version to expermient with

If you are interested in contributing, please contact me on reddit @ /u/philipwithpostral or open an issue with suggestions or corrections.

This is a work in progress and under active development. It is not suited for production use. USE AT YOUR OWN RISK! If you find bugs, please open an issue!

Goals

  • Provide a complete reference implementation for the essential functions of a small retail-facing brokerage operation.
  • Enable algorithm developers and novice traders a complete brokerage-in-a-box experience without risking any capital.
  • Educate and inform newcomers about how a brokerage operation works, manages positions, fills orders and calculates margins.

Installing paperbroker

If you are going to use paperbroker as a package, install it directly from git.

  1. pip install git+https://github.com/philipodonnell#egg=paperbroker

If you are going to use paperbroker as an HTTP server, clone it directly

  1. git clone https://github.com/philipodonnell/paperbroker
  2. cd paperbroker
  3. python3 server.py

I recommend and test on Windows 10 and Ubuntu.

Testing

Unit tests are available in /paperbroker/tests. More tests are always appreciated.

To make testing of algorithms and itself easier, PaperBroker includes several days of quotes data for all underlyings and options/chains for the following:

  • AAL between 2017-01-27 and 2017-01-28 (Jan expiration + earnings) and between 2017-03-24 and 2017-03-25 (March expiration)
  • GOOG between 2017-01-27 and 2017-01-28 (Jan expiration) and between 2017-03-24 and 2017-03-25 (March expiration)

To use this data, create your PaperBroker and pass the TestDataQuoteAdapter explicitly

  1. from paperbroker import PaperBroker
  2. from paperbroker.tests.TestDataQuoteAdapter import TestDataQuoteAdapter
  3. # instantiate the test data adapter
  4. test_data = TestDataQuoteAdapter()
  5. #control which dates are currently effective
  6. test_data.current_date = '2017-01-27'
  7. # pass the test data adapter explicitly
  8. broker = PaperBroker(quote_adapter=test_data)
  9. # now all broker functions (quotes/orders/etc...) will act as if it is Jan 27, 2017
  10. broker.get_quote('AAL')
  11. # >> 2017-01-27 47.35
  12. # change the effective date
  13. test_data.current_date = '2017-01-28'
  14. # now all broker functions (quotes/orders/etc...) will act as if it is Jan 28, 2017
  15. broker.get_quote('AAL')
  16. # >> 2017-01-28 46.90

Usage Examples

These illustrate the basic ordering flow of PaperBroker when used as a package with the stock GoogleFinance quote data.
Many (but not all) of these functions are available through the HTTP api. See /paperbroker/server.py for more details

  1. from paperbroker import PaperBroker
  2. from paperbroker.orders import Order
  3. # Creating a PaperBroker defaults to:
  4. # - uses the local filesystem temp folder to store acounts
  5. # - quotes from Google Finance (equities only)
  6. # - estimates all transaction prices at the midpoint
  7. # - you can change any of these by writing your own adapters, see paperbroker/adapters
  8. broker = PaperBroker()
  9. # Create an account so we can buy stuff
  10. account = broker.open_account()
  11. account.cash = 100000 # give ourselves some cash!!
  12. # This is how we get basic quotes
  13. # We can get any quotes supported by GoogleFinance
  14. quote = broker.get_quote('GOOG')
  15. print(quote.price)
  16. # >> 943.83
  17. # Get the expiration dates that GoogleFinance has for GOOG
  18. expiration_dates = broker.get_expiration_dates('GOOG')
  19. print(expiration_dates)
  20. # >> ['2018-01-19']
  21. # Get all of the options that we have for the next chain
  22. quotes = broker.get_options('GOOG', expiration_dates[0])
  23. print(len(quotes), quotes)
  24. # >> 118 [<paperbroker.quotes.OptionQuote object at 0x0000008C13F41FD0>, ..]
  25. # Get the 50 delta call implied volatility and strike
  26. call_quotes = [q for q in quotes if q.asset.option_type == 'call' and q.has_greeks()]
  27. fifty_delta_call_quote = sorted(call_quotes, key=lambda q:abs(0.5 - abs(q.delta)))[0]
  28. print(fifty_delta_call_quote.asset.symbol, fifty_delta_call_quote.bid, fifty_delta_call_quote.ask, fifty_delta_call_quote.asset.strike, fifty_delta_call_quote.iv)
  29. # >> GOOG180119C00960000 51.0 52.6 960.0 0.20861707425282885
  30. # Create a market order to buy-to-open this option
  31. # straightforward orders have shortcuts
  32. broker.buy_to_open(account=account, asset=fifty_delta_call_quote.asset, quantity=1)
  33. print(account.cash, account.maintenance_margin, len(account.positions))
  34. # >> 94820.0 0.0 1
  35. # while we're here, lets also sell an ATM call on the same expiration and buy some stock for a covered call
  36. atm_call_quote = sorted(call_quotes, key=lambda q:abs(quote.price - q.asset.strike))[0]
  37. print(atm_call_quote.asset.symbol, atm_call_quote.bid, atm_call_quote.ask, atm_call_quote.asset.strike, atm_call_quote.iv)
  38. # >> GOOG180119C00940000 61.1 63.0 940.0 0.21215993354358822
  39. # covered calls require custom orders (for now, help at /paperbroker/orders.py)
  40. covered_call_order = Order()
  41. covered_call_order.add_leg(asset='GOOG', quantity=100, order_type='bto')
  42. covered_call_order.add_leg(asset=atm_call_quote.asset.symbol, quantity=-1, order_type='sto')
  43. # simulation is not required, but its recommended to see what state you'll be in afterwards
  44. # for more complex orders
  45. simulated_account = broker.simulate_order(account, covered_call_order)
  46. print(account.cash, account.maintenance_margin, len(account.positions))
  47. # >> 94820.0 0.0 1
  48. # enter the covered call order
  49. broker.enter_order(account, covered_call_order)
  50. print(account.cash, account.maintenance_margin, len(account.positions))
  51. # >> 6642.0 0.0 3
  52. # now imagine a little time has passed and we need some cash. That covered call is holding a lot of capital!
  53. # let sell the stock part
  54. # notice afterwards that our cash is higher but out maintenance margin has increased by a few thousand dollars
  55. # this is because the short call was covered by the stock so it had no margin requirement
  56. # we sold the stock so now its covered by the ATM long call and treated as a vertical spread
  57. broker.sell_to_close(account, 'GOOG', -100)
  58. print(account.cash, account.maintenance_margin, len(account.positions))
  59. # >> 101025.0 2000.0 2
  60. # Lets sell the atm long call as well
  61. # we'll need to find it in the position list
  62. long_call_position = [_ for _ in account.positions if _.asset == fifty_delta_call_quote.asset][0]
  63. # there is a shortcut to close existing positions by passing them to the broker directly
  64. # once we sell this long call we will be left with the naked short call from the covered call
  65. # the maintenance margin is null because we don't have an implementation for naked call margin yet
  66. # check out paperbroker/logic/maintenance_margin.py if you can help
  67. broker.close_position(account, long_call_position)
  68. print(account.cash, account.maintenance_margin, len(account.positions))
  69. # >> 106205.0 None 1
  70. # and finally liquidate everything and back to normal
  71. broker.close_positions(account, account.positions)
  72. print(account.cash, account.maintenance_margin, len(account.positions))
  73. # >> 100000.0 0.0 0

Credits

Special thanks to the folks at https://www.reddit.com/r/options