QTPyLib, Pythonic Algorithmic Trading¶
QTPyLib (Quantitative Trading Python Library) is a simple, event-driven algorithmic trading system written in Python 3, that supports backtesting and live trading using Interactive Brokers for market data and order execution.
I originally developed QTPyLib because I wanted for a simple (but powerful) trading library that will let me to focus on the trading logic itself and ignore everything else.
- A continuously-running Blotter that lets you capture market data even when your algos aren’t running.
- Tick, Bar and Trade data is stored in MySQL for later analisys and backtesting.
- Using pub/sub architecture using ØMQ (ZeroMQ) for communicating between the Algo and the Blotter allows for a single Blotter/multiple Algos running on the same machine.
- Support for Order Book, Quote, Time, Tick or Volume based strategy resolutions.
- Includes many common indicators that you can seamlessly use in your algorithm.
- Market data events uses asynchronous, non-blocking architecture.
- Have orders delivered to your mobile via SMS (requires a Nexmo or Twilio account).
- Full integration with TA-Lib via dedicated module (see documentation).
- Ability to import any Python library (such as scikit-learn or TensorFlow) to use them in your algorithms.
There are 5 main components to QTPyLib:
Blotter- handles market data retreival and processing.
Broker- sends and proccess orders/positions (abstracted layer).
Algo- (sub-class of
Broker) communicates with the
Blotterto pass market data to your strategies, and proccess/positions orders via
Reports- provides real time monitoring of trades and open opsitions via Web App, as well as a simple REST API for trades, open positions and market data.
- Lastly, Your Strategies, which are sub-classes of
Algo, handle the trading logic/rules. This is where you’ll write most of your code.
1. Get Market Data¶
To get started, you need to first create a Blotter script:
# blotter.py from qtpylib.blotter import Blotter class MainBlotter(Blotter): pass # we just need the name if __name__ == "__main__": blotter = MainBlotter() blotter.run()
Then, with IB TWS/GW running, run the Blotter from the command line:
$ python blotter.py
If your strategy needs order book / market depth data, add the
--orderbook flag to the command:
$ python blotter.py --orderbook
2. Write your Algorithm¶
While the Blotter running in the background, write and execute your algorithm:
# strategy.py from qtpylib.algo import Algo class CrossOver(Algo): def on_start(self): pass def on_fill(self, instrument, order): pass def on_quote(self, instrument): pass def on_orderbook(self, instrument): pass def on_tick(self, instrument): pass def on_bar(self, instrument): # get instrument history bars = instrument.get_bars(window=100) # or get all instruments history # bars = self.bars[-20:] # skip first 20 days to get full windows if len(bars) < 20: return # compute averages using internal rolling_mean bars['short_ma'] = bars['close'].rolling_mean(window=10) bars['long_ma'] = bars['close'].rolling_mean(window=20) # get current position data positions = instrument.get_positions() # trading logic - entry signal if bars['short_ma'].crossed_above(bars['long_ma'])[-1]: if not instrument.pending_orders and positions["position"] == 0: # buy one contract instrument.buy(1) # record values for later analysis self.record(ma_cross=1) # trading logic - exit signal elif bars['short_ma'].crossed_below(bars['long_ma'])[-1]: if positions["position"] != 0: # exit / flatten position instrument.exit() # record values for later analysis self.record(ma_cross=-1) if __name__ == "__main__": strategy = CrossOver( instruments = [ ("ES", "FUT", "GLOBEX", "USD", 201609, 0.0, "") ], # ib tuples resolution = "1T", # Pandas resolution (use "K" for tick bars) tick_window = 20, # no. of ticks to keep bar_window = 5, # no. of bars to keep preload = "1D", # preload 1 day history when starting timezone = "US/Central" # convert all ticks/bars to this timezone ) strategy.run()
To run your algo in a live enviroment, from the command line, type:
$ python strategy.py --logpath ~/qtpy/
The resulting trades be saved in
~/qtpy/STRATEGY_YYYYMMDD.csv for later analysis.
3. Viewing Live Trades¶
While the Blotter running in the background, write the dashboard:
# dashboard.py from qtpylib.reports import Reports class Dashboard(Reports): pass # we just need the name if __name__ == "__main__": dashboard = Dashboard(port = 5000) dashboard.run()
To run your dashboard, run it from the command line:
$ python dashboard.py >>> Dashboard password is: a0f36d95a9 >>> Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
Now, point your browser to http://localhost:5000 and use the password generated to access your dashboard.
Please refer to the Full Documentation to learn how to enable SMS notifications, use the bundled Indicators, and more.
$ pip install qtpylib --upgrade --no-cache-dir
- Python >=3.4
- Pandas (tested to work with >=0.18.1)
- Numpy (tested to work with >=1.11.1)
- PyZMQ (tested to with with >=15.2.1)
- PyMySQL (tested to with with >=0.7.6)
- pytz (tested to with with >=2016.6.1)
- dateutil (tested to with with >=2.5.1)
- Nexmo-Python for SMS support (tested to with with >=1.2.0)
- Twilio-Python for SMS support (tested to with with >=5.4.0)
- Flask for the Dashboard (tested to work with >=0.11)
- Requests (tested to with with >=2.10.0)
- Beautiful Soup (tested to work with >=4.3.2)
- IbPy2 (tested to work with >=0.8.0)
- ezIBpy (IbPy wrapper, tested to with with >=1.12.56)
- Latest Interactive Brokers’ TWS or IB Gateway installed and running on the machine
- MySQL Server installed and running with a database for QTPyLib
QTPyLib is distributed under the GNU Lesser General Public License v3.0. See the LICENSE.txt file in the release for details. QTPyLib is not a product of Interactive Brokers, nor is it affiliated with Interactive Brokers.
You can find other examples in the qtpylib/examples directory.
I’m very interested in your experience with QTPyLib. Please drop me an note with any feedback you have.