Professional Documents
Culture Documents
Release latest
Ran Aroussi
1 Features 3
2 Quickstart 5
3 Installation 9
4 Legal Stuff 11
i
ii
QTPyLib Documentation, Release latest
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.
Full Documentation »
Contents 1
QTPyLib Documentation, Release latest
2 Contents
CHAPTER 1
Features
• 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.
• Includes many common indicators that you can seamlessly use in your algorithm.
• Ability to import any Python library (such as scikit-learn or TA-Lib) to use them in your algorithms.
• Have orders delivered to your mobile via SMS (requires a Nexmo or Twilio account)
3
QTPyLib Documentation, Release latest
4 Chapter 1. Features
CHAPTER 2
Quickstart
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
While the Blotter running in the background, write and execute your algorithm:
# strategy.py
from qtpylib.algo import Algo
5
QTPyLib Documentation, Release latest
class CrossOver(Algo):
def on_start(self):
pass
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,
bar_window = 5,
preload = "1D",
timezone = "US/Central"
)
strategy.run()
6 Chapter 2. Quickstart
QTPyLib Documentation, Release latest
To run your algo in a live enviroment, from the command line, type:
$ python strategy.py --logpath ~/qtpy/
class Dahboard(Reports):
pass # we just need the name
if __name__ == "__main__":
dashboard = Dahboard(port = 5000)
dashboard.run()
Now, point your browser to http://localhost:5000 and use the password generated to access your dashboard.
Note: Please refer to the Full Documentation to learn how to enable SMS notifications, use the bundled Indicators,
and more.
8 Chapter 2. Quickstart
CHAPTER 3
Installation
First, install IbPy (for some reason I can’t get this installed automatically):
$ pip install git+git://github.com/blampe/IbPy --user
3.1 Requirements
• Python >=3.4
• Pandas (tested to work with >=0.18.1)
• Numpy (tested to work with >=1.11.1)
• ØMQ (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 for SMS support (tested to with with >=1.2.0)
• Twilio 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)
• IbPy (tested to work with >=0.7.2-9.00)
• ezIBpy (IbPy wrapper, tested to with with >=1.12.1)
• Latest Interactive Brokers’ TWS or IB Gateway installed and running on the machine
9
QTPyLib Documentation, Release latest
10 Chapter 3. Installation
CHAPTER 4
Legal Stuff
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.
4.1 P.S.
I’m very interested in your experience with QTPyLib. Please drop me an note with any feedback you have.
Ran Aroussi
4.2.1 Installation
Note: QTPyLib requires IbPy, which, for some reason, cannot be bundled with the pip installer and requires manual
installation. To install IbPy manually, run:
$ pip install git+git://github.com/blampe/IbPy --user
Uninstall QTPyLib
11
QTPyLib Documentation, Release latest
Requirements
• Python >=3.4
• Pandas (tested to work with >=0.18.1)
• Numpy (tested to work with >=1.11.1)
• ØMQ (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 for SMS support (tested to with with >=1.2.0)
• Twilio 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)
• IbPy (tested to work with >=0.7.2-9.00)
• ezIBpy (IbPy wrapper, tested to with with >=1.12.1)
• Latest Interactive Brokers’ TWS or IB Gateway installed and running on the machine
In order for QTPyLib to be able to subscribe to market data and submit orders, you must have the latest version of
Interactive Brokers’ TWS or IB Gateway installed, running and properly configured on your machine.
Installation
Download TWS (offline version) or IB Gateway (requires less resources = recommended) from Interactive Brokers’
website, and follow the installation instructions.
• Download TWS (Traders Workstation)
• Download IB Gateway
After you install either TWS or IBGW, login using your account (or use edemo/demouser). The next thing to do is
to go to the menu, choose File, then choose Global Configuration.
Next, choose API on the left hand side, then go to Settings.
In the settings screen, make sure to set the options highlighted in the screenshot below:
Next, go to Precautions on the left side menu, and make sure *Bypass Order Precautions for API Orders is
checked.
Now that your system is setup, it’s time to start programming your Algo...
Flow Chart
Market Data retrieval is done by a piece of software called a Blotter. A Blotter connects to the broker (in QTPyLib’s
case, Interactive Brokers via TWS/IB), handles incoming market data and passes it to the algo for processing.
Blotters optionally (but usually) also take care of storing the market data in a Database for later analysis, back-testing
new strategies, etc.
In QTPyLib’s case, the Blotter handle all of the above, while your algorithms subscribe to the Blotter’s updates via
pub/sub mechanism using ZeroMQ - a blazing fast Message Queue.
Note: QTPyLib was designed with a “One Blotter To Rule Them All” design in mind. All your algorithms can
listen to a single Blotter running in the background without a problem and without consuming any unnessecery system
resources. Simply put: do not run multiple Blotters unless you have a very specific reason to do so.
The first thing you need to do is to create the MySQL database where your Blotter will store tick and minute data for
later use.
Once you’ve created the database, note its name for the next step. The Blotter will automatically create the required
database tables when it runs for the first time.
To get started writing your Blotter, you’ll need to create a Blotter object sub-class and name it.
Then, inililize your Blotter by passing your MySQL credentials and TWS/IBGW port and run it.
# blotter.py
from qtpylib.blotter import Blotter
class MainBlotter(Blotter):
pass # we just need the name
if __name__ == "__main__":
blotter = MainBlotter(
dbhost = "localhost",
dbname = "qtpy",
dbuser = "master",
dbpass = "blaster",
ibport = 4001, # 7496/7497 = TWS, 4001 = IBGateway
)
blotter.run()
With IB TWS/GW running, run the Blotter from the command line:
$ python blotter.py
You can also override the initilized paramters (or ommit this part of the code altogether) and pass runtime parameters
using the command line.
In this case, your code would look something like this:
# blotter.py
from qtpylib.blotter import Blotter
class MainBlotter(Blotter):
pass # we just need the name
if __name__ == "__main__":
blotter = MainBlotter()
blotter.run()
Then, run the Blotter by passing the parameters via the command line:
$ python blotter.py [--dbport] [--dbname] [--dbuser] [--dbpass] [--ibport] [...]
Available Arguments
Below are all the parameters that can either be set via the Blotter() initilizer or via CLI:
• --symbols CSV database of IB contracts for market data fetching (default: ./symbols.csv)
• --ibport TWS/IBGW Port to use (default: 4001)
• --ibclient TWS/IBGW Client ID (default: 999)
• --ibserver IB TWS/GW Server hostname (default: localhost)
• --zmqport ØMQ Port to use (default: 12345)
• --dbhost MySQL server hostname (default: localhost)
• --dbport MySQL server port (default: 3306)
• --dbname MySQL server database (default: qtpy)
• --dbuser MySQL server username (default: root)
• --dbpass MySQL server password (default: None)
• --dbskip [flag] Skip MySQL logging of market data (default: False)
Instruments CSV
Once your Blotter runs for the first time, you’ll notice that a new file named symbols.csv has been created in the
same directory as your Blotter.
This fill will store all the instruments that algos connecting to this Blotter will request data for. Your blotter will keep
logging market data for these instruments even when you stop your algos so you have continious market data stored
in your database for future research and backtesting (expired product will be deleted automatically from this file).
You can, of course, add or delete unwanted instruments from the CSV file manually at any time – without stopping
your Blotter.
Eample a populated symbols.csv file:
symbol,sec_type,exchange,currency,expiry,strike,opt_type
AAPL,STK,SMART,USD,,0.0,
ES,FUT,GLOBEX,USD,201609,0.0,
NFFX,OPT,SMART,USD,20160819,98.50,PUT
With your Blotter running, its time to write your first Algo...
When creating your algorithm, there are two functions that handles incoming market data from the running Blotter.
These are on_tick() which is invoked on every tick captured, and on_bar(), which is invoked on every bar
created in the pre-specified resolution. An Instruments Object is being passed to each method when called.
If you need to set some parameters when your strategy starts, simply add an on_start() method to your strategy,
and set your parameters there.
All three methods are optional. You can run logic on start and/or on every tick and/or on every bar event as needed.
Unnecessary can either use pass or be ommited from your strategy code.
Warning: You’re going to lose a lot of money very quickly by running the sample algorithms in this docu-
mentation! Please use the demo account when logging into IB TWS / IB Gateway (user: edemo, password:
demouser).
Here’s a code for an algo that buys Apple Stock when flat and sells when in position.
# strategy.py
from qtpylib.algo import Algo
class DumbAlgo(Algo):
def on_start(self):
# optional method that gets called once upon start
pass
if __name__ == "__main__":
With your Blotter running in the background, run your algo from the command line:
$ python strategy.py
The algo will communicate with the Blotter running in the background and generate orders based on the rules specified.
Note: A trade log will be saved in the database specified in the currently running Blotter and will be available via the
Reporting Web App / API.
While the Blotter running in the background, write and execute your algorithm:
# strategy.py
from qtpylib.algo import Algo
class CrossOver(Algo):
elif bars['short_ma'].crossed_below(bars['long_ma'])[-1]:
if positions["position"] != 0:
if __name__ == "__main__":
strategy = CrossOver(
instruments = [ ("CL", "FUT", "NYMAX", "USD", 201609) ],
resolution = "1H"
)
strategy.run()
With your Blotter running in the background, run your algo from the command line:
$ python strategy.py --log ~/qtpy/
By adding --log ~/qtpy/ we ask that the resulting trade journal be saved in
~/qtpy/STRATEGY_YYYYMMDD.csv for later analysis in additioan to being saved in the database.
# strategy.py
from qtpylib.algo import Algo
class BuyStockSellOil(Algo):
es_pos = ES.get_positions()
cl_pos = CL.get_positions()
if __name__ == "__main__":
strategy = BuyStockSellOil(
instruments = [
strategy.run()
Initializing Parameters
Sometimes you’d want to set some parameters when you initlize your Strategy. To do so, simply add an on_start()
method to your strategy, and set your parameters there. It will be invoked once when you strategy starts.
# strategy.py
from qtpylib.algo import Algo
class MyStrategy(Algo):
def on_start(self):
self.paramA = "a"
self.paramB = "b"
...
Available Arguments
Below are all the parameters that can either be set via the Algo() or via CLI (all are optional).
Algo Parameters
strategy = MyStrategy(
instruments = [ "AAPL" ],
resolution = "512K", # 512 tick bars
tick_window = 10, # keep last 10 ticks bars
In addition to live/paper trading, QTPyLib can also be used for back-testing without changing event one line of code,
simply by adding the following arguments when running your algo.
Note: You MUST have the relevant historical data stored in your Blotter’s database in order to run back-tests - which
is also a good reason to keep your Blotter running for all eternity :)
In addition, when backtesting Futures, the Blotter will stream adjusted, continous contracts for the contracts requested,
based on previously captured market data stored in the Database.
The resulting back-tested portfolio will be saved in ./portfolio.pkl for later analysis.
Recording Data
You can record data from within your algo and make this data available as a csv/pickle/h5 file. You can record whatever
you want by adding this to your algo code (bar data is recorded automatically):
self.record(key=value, ...)
The recorded data (and bar data) will be made availble in ./path/to/recorded-file.csv, which gets updated
in real-time.
Instruments Tuples
When initilizing your algo, you’re required to pass a list of instruments you want to trades. List items can be a Ticker
Symbol String (for US Stocks only) or an Tuple in IB format for other instruments.
Example: US Stocks
instruments = [ "AAPL", "GOOG", "..." ]
For anything other than US Stocks, you must use IB Tuples in the following data information:
(symbol, sec_type, exchange, currency [, expiry [, strike, opt_type]])
Where expiry must be provided for Futures (YYYYMM) and Options (YYYYMMDD) whereas strike and
opt_type must be a provided for Options (PUT/CALL).
Example: UK Stock
instruments = [ ("BARC", "STK", "LSE", "GBP"), (...) ]
For best practice, its recommended that you use the full IB Tuple structure for all types of instruments:
instruments = [
("AAPL", "STK", "SMART", "USD", "", 0.0, ""),
("BARC", "STK", "LSE", "GBP", "", 0.0, ""),
("ES", "FUT", "GLOBEX", "USD", 201609, 0.0, ""),
("NFLX", "OPT", "SMART", "USD", 20160819, 98.50, "PUT"),
("EUR", "CASH", "IDEALPRO", "USD", "", 0.0, ""),
...
]
QTPyLib comes with a basic reporting web app where you can monitor your trade history and open positions. While
the web app is running, it also exposes a simple REST API for fetching trades, market data, etc to create your own
application.
Note: Since QTPyLib relies on Interactive Brokers for pretty much everything, it’s recommended that you create a
second user for your IB account and use it to login to TWS on your computer or Phone. There you can see the trades
made by your algorithms, use the built-in charts, etc.
To get a reporting dashboard up and running, you’ll need to create a Reports object sub-class and name it.
# dashboard.py
from qtpylib.reports import Reports
class Dashboard(Reports):
pass # we just need the name
if __name__ == "__main__":
dashboard = Dashboard(
port = 5000,
blotter = "MainBlotter"
)
dashboard.run()
While the Blotter running in the background, run your dashboard from the command line:
$ python dashboard.py
Point your browser to http://localhost:5000, enter the password, and you should see something like this:
You can also override the initilized paramters (or ommit this part of the code altogether) and pass runtime parameters
using the command line.
In this case, your code would look something like this:
# dashboard.py
from qtpylib.reports import Reports
class Dashboard(Reports):
pass # we just need the name
if __name__ == "__main__":
dashboard = Dashboard()
dashboard.run()
Then, run the Blotter by passing the parameters via the command line:
$ python dashboard.py --port 5000 --blotter MainBlotter --nopass
Available Arguments
Below are the parameters that can either be set via the Reports() initilizer or via CLI:
• --port HTTP port to use (default: 5000)
• --host Host to bind the http process to (defaults to localhost)
• --blotter Use this Blotter’s MySQL server settings (default: auto-detect).
• --nopass [flag] Skip password for web app
REST API
With your web app running, a few REST API endpoints becomes accessible using:
$ curl -i -X GET ENDPOINT
Each endpoints returns an Array of JSON objects with the requested information.
[ {
"algo": "TestStrategy",
"symbol": "ESU2016",
"direction": "LONG",
"quantity": 1,
"entry_time": 1471490411,
"order_type": "MARKET",
"entry_price": 2192.75,
"market_price": 2192.5,
"slippage": -0.25,
"target": 0,
"stop": 0,
"exit_time": 1471490411,
"exit_price": 2192.5,
"exit_reason": "SIGNAL",
"realized_pnl": 0.25,
}, ... ]
Available Endpoints
Algo list:
$ http://localhost:5000/algos
Symbol list:
$ http://localhost:5000/symbols
Trade list:
$ http://localhost:5000/trades
$ http://localhost:5000/trades/start_YY-MM-DD/
$ http://localhost:5000/trades/start_YY-MM-DD/end_YY-MM-DD/
Market data:
$ http://localhost:5000/bars/resolution/symbol
$ http://localhost:5000/bars/resolution/symbol/start_YY-MM-DD/
$ http://localhost:5000/bars/resolution/symbol/start_YY-MM-DD/end_YY-MM-DD/
QTPyLib supports both automatic trade notifications via SMS and custom messages (for example, when you want to
SMS yourself signals without entering a trade).
To specify the recepients, add the --sms flag when running your algo from the command line:
$ python strategy.py --sms +15551230987 +447781123456 ...
Now, whenever your algo generates a trade or when you send custom SMS, these recepients will receive the notification
to their phone.
Note: To enable this functionality, you need to have an account with either Nexmo or Twilio and set an SMS Provider
for your algo (refer to the SMS Service Provider Setup section below).
Trade Notifications
Trades notifications are enabled by default and will be sent whenever your algo makes a trade, as long as you specified
recepients when running the algo.
----
11:39:29 UTC
SLD 2x ESU2016 @ 2178.25 TGT
PL +1.25 (2m 8s)
----
12:47:29 UTC
SLD 2x ESU2016 @ 2174.50 STP
PL -2.50 (1h 10m 8s)
Custom Notifications
Aside from automatic trade notification, you have your algo send custom messages (for example, when you want to
SMS yourself signals without entering a trade).
To do this, add you need to import the SMS module and add this code to your algo:
self.sms("Look ma, custom text msg...")
To enable this functionality, you need to have an account with either Nexmo or Twilio.
Then, simply create a file named sms.ini in the same directory as your strategy.py file with the following
structure:
[nexmo]
key = API_KEY
secret = SECRET_KEY
from = FROM_NUMBER (OPTIONAL)
[twilio]
sid = ACCOUNT_SID
token = AUTH_TOKEN
from = FROM_NUMBER
Note: If your sms.ini file contains both services, QTPyLib will use the first one listed.
Although you can import technical indicator libraries such as the excellent TA-Lib and use them in your strategies,
QTPyLib does comes bundled with some common indicators that work as Pandas Objects.
ATR
Bollinger Bands
bb = bars.bollinger_bands(window=20, stds=2)
bars['bb_upper'] = bb['upper']
bars['bb_lower'] = bb['lower']
bars['bb_mid'] = bb['mid']
...
bars['wbb_upper'] = wbb['upper']
bars['wbb_lower'] = wbb['lower']
bars['wbb_mid'] = wbb['mid']
...
CCI
bars['cci'] = bars.cci(window=14)
...
Crossed Above/Below
bars['sma'] = bars['close'].rolling_mean(10)
if bars['close'].crossed_above(bars['sma']):
...
if bars['close'].crossed_below(bars['sma']):
...
IBS
bars['ibs'] = bars.ibs()
...
Implied Volatility
bars['iv'] = bars.implied_volatility(window=252)
...
Keltner Channel
kc = bars.keltner_channel(window=14, atrs=2)
bars['kc_upper'] = kc['upper']
bars['kc_lower'] = kc['lower']
bars['kc_mid'] = kc['mid']
...
MACD
bars['macd'] = macd['macd']
bars['macd_signal'] = macd['signal']
bars['macd_hist'] = macd['histogram']
...
Moving Average
Price Indicators
bars['mid'] = bars.mid_price()
...
bars['typical'] = bars.typical_price()
...
Rolling Indicators
Min
Max
Mean
Standard Deviation
Weighted Mean
Returns
bars['returns'] = bars.returns()
...
Log Returns
bars['log_returns'] = bars.log_returns()
...
ROC
bars['roc'] = bars.roc(window=14)
...
RSI
bars['rsi'] = bars.rsi(window=14)
...
Session
This isn’t an indicator, but rather a utility that trims the bars to a specified “Session” (useful when wanting to work,
for example, with the most recent PIT or GLOBEX session to calculate VWAP, etc.).
# make sure to specity timezone="US/Central" for your algo
# otherwise, the default timezone is UTC
# pit session
bars = bars.session(start='08:30', end='15:15')
# globex session
bars = bars.session(start='17:00', end='16:00')
...
Stochastics
True Range
bars['tr'] = bars.true_range()
...
VWAP
bars['vwap'] = bars.vwap(bars)
...
If you want to always trade the most active future contract (based on the previous day’s volume and open interest),
you can do so by using the futures.get_active_contract() function to construct your IB contract tuples
specified in your algo.
# strategy.oy
...
if __name__ == "__main__":
# get most active ES contract
ACTIVE_MONTH = futures.get_active_contract("ES")
strategy = CrossOver(
instruments = [ ("ES", "FUT", "GLOBEX", "USD", ACTIVE_MONTH, 0.0, "") ],
...
)
...
Note: This functionality currently works for future contracts traded on the CME only (including CME, GLOBEX,
CBOT, NYMEX and COMEX).
When you want to know a futures contract’s margin requirements, you can call futures.get_ib_margin(...)
to get that information. New data is fetched from IB id cache file doesn’t exist or if it’s older than 24 hours.
# strategy.oy
...
"""
margin returns a dict with the following data:
{
'class': 'NQ',
'currency': 'USD',
'description': 'E-mini NASDAQ 100 Futures',
'exchange': 'GLOBEX',
'has_options': True,
'intraday_initial': 2250.0,
'intraday_maintenance': 1800.0,
'overnight_initial': 4500.0,
'overnight_maintenance': 3600.0,
'symbol': 'NQ'
}
"""
Instrument API
The Instrument object is passed to the on_tick(...) and on_bar(...) methods in your strategy:
# startegy.py
def on_tick(self, instrument):
instrument.MethodName(...)
class qtpylib.instrument.Instrument
A string subclass that provides easy access to misc symbol-related methods and information.
get_bars(lookback=None, as_dict=False)
Get bars for this instrument
Parameters
lookback [int] Max number of bars to get (None = all available bars)
as_dict [bool] Return a dict or a pd.DataFrame object
Retruns
bars [pd.DataFrame / dict] The bars for this instruments
get_ticks(lookback=None, as_dict=False)
Get ticks for this instrument
Parameters
lookback [int] Max number of ticks to get (None = all available ticks)
as_dict [bool] Return a dict or a pd.DataFrame object
Retruns
bars [pd.DataFrame / dict] The ticks for this instruments
order(direction, quantity, **kwargs)
Send an order for this instrument
Parameters
direction [string] Order Type (BUY/SELL, EXIT/FLATTEN)
quantity [int] Order quantity
Optional
limit_price [float] In case of a LIMIT order, this is the LIMIT PRICE
expiry [int] Cancel this order if not filled after n seconds (default 60 seconds)
order_type [string] Type of order: Market (default), LIMIT (default when limit_price is
passed), MODIFY (required passing or orderId)
orderId [int] If modifying an order, the order id of the modified order
target [float] target (exit) price
initial_stop [float] price to set hard stop
trail_stop_at [float] price at which to start trailing the stop
trail_stop_by [float] % of trailing stop distance from current price
ticksize [float] If using traling stop, pass the tick size for the instruments so you won’t try to
buy ES at 2200.128230 :)
market_order(direction, quantity, **kwargs)
Shortcut for instrument.order(...) and accepts all of its optional parameters
Parameters
direction [string] Order Type (BUY/SELL, EXIT/FLATTEN)
quantity [int] Order quantity
limit_order(direction, quantity, price, **kwargs)
Shortcut for instrument.order(...) and accepts all of its optional parameters
Parameters
direction [string] Order Type (BUY/SELL, EXIT/FLATTEN)
quantity [int] Order quantity
price [float] Limit price
buy(quantity, **kwargs)
Shortcut for instrument.order("BUY", ...) and accepts all of its optional parameters
Parameters
quantity [int] Order quantity
buy_market(quantity, **kwargs)
Shortcut for instrument.order("BUY", ...) and accepts all of its optional parameters
Parameters
quantity [int] Order quantity
buy_limit(quantity, price, **kwargs)
Shortcut for instrument.order("BUY", ...) and accepts all of its optional parameters
Parameters
quantity [int] Order quantity
price [float] Limit price
sell(quantity, **kwargs)
Shortcut for instrument.order("SELL", ...) and accepts all of its optional parameters
Parameters
order_type [string] the type order to return: STOP (default), LIMIT, MARKET
Retruns
contract [object] IB Order object of instrument
get_orderbook()
Get orderbook for the instrument
Retruns
contract [pd.DataFrame] orderbook DataFrame for the instrument
get_symbol()
Get symbol of this instrument
Retruns
contract [pd.DataFrame] orderbook DataFrame for the instrument
modify_order(orderId, quantity=None, limit_price=None)
Modify quantity and/or limit price of an active order for the instrument
Parameters
orderId [int] the order id to modify
Optional
quantity [int] the required quantity of the modified order
limit_price [int] the new limit price of the modified order
get_margin_requirement()
Get margin requirements for intrument (futures only)
Retruns
margin [dict] margin requirements for instrument (all values are None for non-futures in-
struments)
get_margin_max_contracts(overnight=True)
Get maximum contracts allowed to trade baed on required margin per contract and current account balance
(futures only)
Parameters
overnight [bool] Calculate based on Overnight margin (set to False to use Intraday margin
req.)
Retruns
contracts [int] maximum contracts allowed to trade (returns None for non-futures)
symbol
(Property) Shortcut to self.get_symbol()
contract
(Property) Shortcut to self.get_contract()
positions
(Property) Shortcut to self.get_positions()
portfolio
(Property) Shortcut to self.get_portfolio()
orders
(Property) Shortcut to self.get_orders()
pending_orders
(Property) Shortcut to self.get_pending_orders()
orderbook
(Property) Shortcut to self.get_orderbook()
margin_requirement
(Property) Shortcut to self.get_margin_requirement()
margin_max_contracts
(Property) Shortcut to self.get_margin_max_contracts()
Algo API
Algo is a Sub-Class of Broker and the Parent Class for your strategies. Aside from algo.run(...), all the other
methods should be called from within your strategy via self.MethodName(...).
For example:
# startegy.py
# record something
self.record(key=value)
Blotter API
Reports API
Broker API
Broker is the Parent Class of Algo, which, in turn, is the Parent Class for your strategies. All the following methods
are available from within your strategy via self.MethodName(...)‘.
In many cases, it may be useful to run your code as a system service (aka “daemon”), so you can start/stop it using a
Cron job, monitor it using Monit, etc. The following is a quick guide on how to turn any Python script into a system
service on Linux and Unix machines.
The first step is to create your Python script (for this example we’ll use blotter.py).
[Service]
Type=idle
ExecStart=/PATH/TO/PYTHON /PATH/TO/blotter.py >/dev/null 2>&1
[Install]
WantedBy=multi-user.target
In order to store the Blotter’s output in a log file, change the ExecStart line to:
ExecStart=/path/to/python /path/to/blotter.py > /path/to/blotter.log 2>&1
Note: In most cases the Python executable is found under /usr/bin/python, but it can be located elsewhere
(for example: /home/user/anaconda3/bin/python). You can run which python to get the path to the
System’s default Python executable.
Now the system file has been defined, we need to reload systemctl:
$ sudo systemctl daemon-reload
$ sudo systemctl enable qtpylib-blotter.service
CGroup: /system.slice/qtpylib-blotter.service
-26737 /usr/bin/python /home/user/blotter.py
QTPyLib is not a product of Interactive Brokers, nor is it affiliated with Interactive Brokers.
QTPyLib is distributed under the GNU Lesser General Public License v3.0.
License Agreement
facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument
passed when the facility is invoked), then you may convey a copy of the modified version:
a) under this License, provided that you make a good faith effort to ensure that, in the event
an Application does not supply the function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of this License applicable to
that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if
the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros,
inline functions and templates (ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the Library is used in it and
that the Library and its use are covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work
and reverse engineering for debugging such modifications, if you also do each of the following:
a) Give prominent notice with each copy of the Combined Work that the Library is used in it
and that the Library and its use are covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license document.
c) For a Combined Work that displays copyright notices during execution, include the copy-
right notice for the Library among these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
4. Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this License,
and the Corresponding Application Code in a form suitable for, and under terms
that permit, the user to recombine or relink the Application with a modified ver-
sion of the Linked Version to produce a modified Combined Work, in the manner
specified by section 6 of the GNU GPL for conveying Corresponding Source.
1) Use a suitable shared library mechanism for linking with the Library. A suit-
able mechanism is one that (a) uses at run time a copy of the Library already
present on the user’s computer system, and (b) will operate properly with a mod-
ified version of the Library that is interface-compatible with the Linked Version.
e) Provide Installation Information, but only if you would otherwise be required to provide such
information under section 6 of the GNU GPL, and only to the extent that such information
is necessary to install and execute a modified version of the Combined Work produced by
recombining or relinking the Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany the Minimal Corresponding
Source and Corresponding Application Code. If you use option 4d1, you must provide the
Installation Information in the manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library facilities that are not Applications and are not covered
by this License, and convey such a combined library under terms of your choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based on the Library, un-
combined with any other library facilities, conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it is a work based on the
Library, and explaining where to find the accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present
version, but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License “or any
later version” applies to it, you have the option of following the terms and conditions either of that published version
or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a
version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General
Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall apply, that proxy’s public statement of
acceptance of any version is permanent authorization for you to choose that version for the Library.
B L
buy() (qtpylib.instrument.Instrument method), 34 limit_order() (qtpylib.instrument.Instrument method), 34
buy_limit() (qtpylib.instrument.Instrument method), 34
buy_market() (qtpylib.instrument.Instrument method), 34 M
margin_max_contracts (qtpylib.instrument.Instrument at-
C tribute), 37
contract (qtpylib.instrument.Instrument attribute), 36 margin_requirement (qtpylib.instrument.Instrument at-
tribute), 37
E market_order() (qtpylib.instrument.Instrument method),
exit() (qtpylib.instrument.Instrument method), 35 34
modify_order() (qtpylib.instrument.Instrument method),
F 36
flatten() (qtpylib.instrument.Instrument method), 35
O
G order() (qtpylib.instrument.Instrument method), 33
orderbook (qtpylib.instrument.Instrument attribute), 37
get_active_order() (qtpylib.instrument.Instrument
orders (qtpylib.instrument.Instrument attribute), 36
method), 35
get_bars() (qtpylib.instrument.Instrument method), 33 P
get_contract() (qtpylib.instrument.Instrument method),
35 pending_orders (qtpylib.instrument.Instrument attribute),
get_margin_max_contracts() (qt- 37
pylib.instrument.Instrument method), 36 portfolio (qtpylib.instrument.Instrument attribute), 36
get_margin_requirement() (qtpylib.instrument.Instrument positions (qtpylib.instrument.Instrument attribute), 36
method), 36
get_orderbook() (qtpylib.instrument.Instrument method), S
36 sell() (qtpylib.instrument.Instrument method), 34
get_orders() (qtpylib.instrument.Instrument method), 35 sell_limit() (qtpylib.instrument.Instrument method), 35
get_pending_orders() (qtpylib.instrument.Instrument sell_market() (qtpylib.instrument.Instrument method), 35
method), 35 symbol (qtpylib.instrument.Instrument attribute), 36
get_portfolio() (qtpylib.instrument.Instrument method),
35
get_positions() (qtpylib.instrument.Instrument method),
35
get_symbol() (qtpylib.instrument.Instrument method), 36
get_ticks() (qtpylib.instrument.Instrument method), 33
I
Instrument (class in qtpylib.instrument), 33
43