Questrade API wrapper.
Project description
Introduction
Pretty versatile Questrade API wrapper. For details about the input parameters and output results, please visit the Questrade API documentation.
Also includes an executable module that determines the ACB (Average/Adjusted Cost Base) of buy and sell activities from saved logs, and prints the profit/loss amounts of sell transactions up till, but not including, a given cut-off year. As a conveninence, you may use the readily available Web application kwessACB for secure and confidential on-the-fly determination of the ACB-based profit/loss values of your Questrade investments.
To install:
python -m pip install kwess
Usage Example
import kwess
from datetime import datetime as dt
from pprint import pprint
# It is assumed that your manually generated token has been saved in local file
# my_token.txt
qs = kwess.Trader(rt_file="my_token.txt", verbose="v")
# Alternatively, if you want to provide the token directly, do this instead
#qs = kwess.Trader(store_tokens=False, token='my-token-here')
accs = qs.get_accounts()
for acc in accs:
print(acc, "\n")
accn = qs.find_account_number("tfsa")
print(accn)
# Get account activities from 1/12/1999 to 28/9/2022
accs = qs.get_account_activities(startdatetime=dt(year=1999, month=12, day=1), \
enddatetime=dt(year=2022, month=9, day=28), verbose="xxx")
for acc in accs:
print(acc, "\n")
# Get (all types of) TFSA account orders from 17/8/2022 to now
# Questrade does not seem to keep old account orders - only the most recent
accs = qs.get_account_orders(startdatetime=dt(year=2022, month=8, day=17), \
verbose="vv")
for acc in accs:
print(acc, "\n")
# Get margin account orders that are still open
accs = qs.get_account_orders(accounttype="margin", startdatetime=dt(year=2022, \
month=7, day=28), enddatetime=dt.now(), statefilter="opened", verbose="333")
for acc in accs:
print(acc, "\n")
ords = qs.get_account_orders_by_ids(accounttype="tfsa", orderid="1088713788", \
verbose="b")
pprint(ords)
ords = qs.get_account_orders_by_ids(orderid="1098747429,1088752426,1088713788", \
verbose="aa")
pprint(ords)
ords = qs.get_account_orders_by_ids(orderid=1098747429)
pprint(ords)
# Get the current time from the API server
dto = qs.get_server_time()
print(dto[0])
print(dto[1])
# Questrade does not seem to keep old account executions - only the most recent
excs = qs.get_account_executions(startdatetime=dt(year=2022, month=1, day=28), \
enddatetime=dt(year=2022, month=9, day=30), verbose="o")
for exc in excs:
print(exc, "\n")
accs = qs.get_account_balances()
print(accs)
accs = qs.get_account_positions(verbose="d")
print(accs)
sim = qs.search_symbols("vfv", verbose="88")
print(sim)
sim = qs.get_symbols_by_names("xdiv.to,xuu.to,qqc.to", verbose="**")
print(sim)
sim = qs.get_symbols_by_names("hom.un.to")
print(sim)
sim = qs.get_symbols_by_ids(26070347, verbose="e")
print(sim)
sim = qs.get_symbols_by_ids("26070347,12890,8953192,18070692", verbose="ee")
print(sim)
sim = qs.get_symbol_options(12890, verbose="s")
pprint(sim)
mks = qs.get_markets()
pprint(mks)
mks = qs.get_market_quotes(12890,verbose="zz")
print(mks)
mks = qs.get_market_quotes("26070347,12890,8953192,18070692", verbose="h")
print(mks)
ops = qs.get_market_quotes_options(option_ids=[9907637,9907638])
pprint(ops)
Sample Script To Pull Your Questrade Logs
from kwess import Trader
from datetime import datetime as dt
import json
def get_logs(qt, startdate, enddate=None, accounttype="TFSA"):
"""
Parameters:
- qt Trader object.
- startdate datetime object for beginning period.
- enddate datetime object for end period. Defaults to None, which will be treated as now.
- accounttype type of account for which activities will be obtained. Defaults to TFSA.
"""
if enddate == None:
enddate = dt.now()
for filename in ["activities", "orders", "executions"]:
filename = ''.join([accounttype, "_account_", filename, "_from_", str(startdate.date()), "_to_", str(enddate.date()), ".json"])
with open(filename, mode="at", encoding="utf-8") as jfp:
if "activities" in filename:
accs = qt.get_account_activities(accounttype=accounttype, startdatetime=startdate, enddatetime=enddate, verbose="nnn")
elif "orders" in filename:
accs = qt.get_account_orders(accounttype=accounttype, startdatetime=startdate, enddatetime=enddate, verbose="nnn")
else:
accs = qt.get_account_executions(accounttype=accounttype, startdatetime=startdate, enddatetime=enddate, verbose='nnn')
for acc in accs:
json.dump(acc, jfp, ensure_ascii=False, indent=2)
if __name__ == "__main__":
#account_types = ["TFSA", "Cash", "Margin"]
#account_types = ["Cash"]
account_types = ["Margin"]
qt = Trader(verbose='n')
for acc_type in account_types:
get_logs(qt=qt, accounttype=acc_type, startdate=dt(year=2025, month=9, day=17))
API Class And Methods
class Trader
__init__(self, rt_file="refreshToken", store_tokens=True, token='', api_server='', server_type="live", timeout=15, verbose='')
Description:
Initializer of a Trader object. Before creating a Trader object for the very first time,
you must obtain a token from your Questrade APP HUB by either:
- generating a new (refresh) token via manual authorization, and save that manually
generated token in a local file. That local file's filename (or pathname) is passed
to rt_file.
or
- perform an Implicit Authorization (via a Mobile Apps or Web applications that run solely
on the user's device) and pass the returned access_token or refresh_token to this initializer
via token.
When Trader creates a Trader object, it could either interact with the API server directly
if token is an access token, or else exchange token (a refresh token) for a new access token
and a new refresh token pair. The access token expires in 30 minutes, while the refresh token
expires in three days.
As long as the refresh token has not expired, creating Trader objects or calling method
get_new_refresh_token will obtain a new access token (if the current access token has
expired) and obtain a new replacement refresh token that will last for another 3 days.
Technically, as long as the current refresh token has not expired, it is possible
to keep exchanging the current refresh token for a new access token and new refresh
token pair indefinitely (by creating Trader objects or calling method get_new_refresh_token).
If the refresh token ever expires, you must repeat the token acquisition process.
Parameters:
- rt_file name of your local file containing your refresh token. In order to use rt_file,
store_tokens has to be set to True. Defaults to "refreshToken".
- store_tokens determines whether tokens are stored into local files or not.
Defaults to True.
- token pass the token (access_token or refresh_token) obtained via Implicit Authorization,
if it won't be taken from a local file. In order to use token, store_tokens has to be set to
False. Defaults to empty string.
- api_server address of the server obtained via Implicit Authorization. It is required if
store_tokens is set to False. Defaults to empty string.
- server_type could be 2 possible values: "live" or "test". "live" will allow you to
interact with your real Questrade account. "test" is for interacting with your test
account. Defaults to "live".
- timeout number of seconds to wait for the server to respond before giving up.
Defaults to 15 seconds. Set timeout to None if you wish to wait forever for a response.
- verbose level of verbosity represented by the number of characters in a string.
Defaults to empty string. Maximum verbosity is 1 or "v". Not useful if store_tokens is False.
Returns:
Trader object.
get_access_token(self):
Description:
Returns the access token.
get_refresh_token(self):
Description:
Returns the refresh token. Note: An empty string will be returned if the Trader object
was initialized with an access token.
build_datetime_string(self, adatetime=None, gmt=False)
Description:
Higher level helper method used to build a Questrade datetime string.
Parameters:
- adatetime a datetime object. Defaults to now.
- gmt optional boolean indicating if datetime is Greenwich Mean Time.
Default value is False.
Returns:
A Questrade datetime string.
find_account_number(self, accounttype)
Description:
Finds the account number corresponding to account type.
Parameters:
- accounttype the type of account. Example "tfsa", "margin", etc.
Returns:
An account number in string format.
get_account_activities(self, startdatetime, enddatetime=None, accounttype='TFSA',
verbose='')
Description:
Generator that returns the account activities from the account related to account
type accounttype, between the range specified by startdatetime and enddatetime.
Both objects are datetime objects.
Parameters:
- startdatetime datetime object specifying the start of a range.
- enddatetime optional datetime object specifying the end of a range.
Defaults to now if not specified.
- accounttype type of Questrade account.
Defaults to "tfsa".
- verbose level of verbosity represented by the number of characters in a string.
Defaults to empty string. Maximum verbosity is 3 or "vvv".
Yields:
The account activities as a Python object representation of the returned json,
between the range startdatetime and enddatetime, in chunks of 30 days.
get_account_balances(self, accounttype='TFSA', verbose='')
Definition:
Provides the account balances for the account related to account type
accounttype.
Paramaters:
- accounttype type of Questrade account.
Defaults to "tfsa".
- verbose level of verbosity represented by the number of characters in
a string.
Defaults to empty string. Maximum verbosity is 2 or "vv".
Returns:
Account balances as a Python object representation of the returned json.
get_account_executions(self, startdatetime, enddatetime=None,
accounttype='TFSA', verbose='')
Description:
Generator that provides account executions from the account related to
account type accounttype, between the range specified by startdatetime and
enddatetime. Both objects are datetime objects.
Parameters:
- startdatetime datetime object representing the beginning of a range.
- enddatetime datetime object representing the end of a range.
Defaults to now if not specified.
- accounttype type of Questrade account.
Defaults to "tfsa".
- verbose level of verbosity represented by the number of characters in
a string.
Defaults to empty string. Maximum verbosity is 3 or "vvv".
Yields:
Account executions as a Python object representation of the returned json,
between the range startdatetime and enddatetime, in chunks of 30 days.
get_account_orders(self, startdatetime, enddatetime=None, accounttype='TFSA',
statefilter='All', verbose='')
Description:
Generator that provides the account orders from the account related to
account type accounttype, between the range specified by startdatetime and
enddatetime. Both objects are datetime objects.
Parameters:
- startdatetime datetime object representing the beginning of a range.
- enddatetime optional datetime object representing the end of a range.
Defaults to now if not specified.
- accounttype type of Questrade account.
Defaults to "tfsa".
- statefilter can be used to specify the state of orders.
It has 3 possible values: Opened, Closed, or All.
Defaults to "All".
- verbose level of verbosity represented by the number of characters in a string.
Defaults to empty string. Maximum verbosity is 3 or "vvv".
Yields:
Account orders as a Python object representation of the returned json,
between the range startdatetime and enddatetime, in chunks of 30 days.
get_account_orders_by_ids(self, orderid, accounttype='TFSA', verbose='')
Description:
Provides the account orders, specified by orderid, from the account related to
account type accounttype.
Parameters:
- orderid is a string of one or many orderid numbers. Several orderid numbers are
seperated by commas (with no spaces). A single orderid could be passed as
a numeral instead of a string.
- accounttype type of Questrade account.
Defaults to "tfsa".
- verbose level of verbosity represented by the number of characters in a string.
Defaults to empty string. Maximum verbosity is 2 or "vv".
Returns:
Account orders as a Python object representation of the returned json.
get_account_positions(self, accounttype='TFSA', verbose='')
Definition:
Provides the account positions for the account related to account type
accounttype.
Paramaters:
- accounttype type of Questrade account.
Defaults to "tfsa".
- verbose level of verbosity represented by the number of characters in a string.
Defaults to empty string. Maximum verbosity is 2 or "vv".
Returns:
Account positions as a Python object representation of the returned json.
get_accounts(self, verbose='')
Description:
Generator that provides the accounts.
Parameters:
- verbose level of verbosity represented by the number of characters in a string.
Defaults to empty string. Maximum verbosity is 1 or "v".
Yields:
All your Questrade accounts as a Python object representation of the returned
json.
get_market_candles(self, sid, interval, startdatetime, enddatetime=None,
verbose='')
Description:
Provides a list of json formatted market candles.
Parameters:
- sid symbol id as a string or numeral.
- interval is the Historical Data Granularity.
Examples: "OneMinute", "HalfHour", "OneYear".
- startdatetime datetime object representing the beginning of a range.
- enddatetime datetime object representing the end of a range.
Defaults to now if not specified.
- verbose level of verbosity represented by the number of characters in a string.
Defaults to empty string. Maximum verbosity is 2 or "vv".
Returns:
Historical market data in the form of OHLC candlesticks for a specified symbol
as a Python object representation of the returned json.
This call is limited to returning 2,000 candlesticks in a single response.
sid is a symbol id.
get_market_quotes(self, ids, verbose='')
Definition:
Provides market quotes data.
Parameter:
- ids Internal symbol identifier. Could be a single value or a string of values.
- verbose level of verbosity represented by the number of characters in a string.
Defaults to empty string. Maximum verbosity is 2 or "vv".
Returns:
A single Level 1 market data quote for one or more symbols in json string format
as a Python object representation of the returned json.
IMPORTANT NOTE: Questrade user needs to be subscribed to a real-time data
package, to receive market quotes in real-time, otherwise call to get quote
is considered snap quote and limit per market can be quickly reached.
Without real-time data package, once limit is reached, the response will return
delayed data. (Please check "delay" parameter in response always).
get_market_quotes_options(self, option_ids, filters=None, verbose='')
Definition:
Provides market quotes options.
Parameters:
- option_ids is a list of stock option ids.
- filters optional list of dictionary items.
- verbose level of verbosity represented by the number of characters in a string.
Defaults to empty string. Maximum verbosity is 2 or "vv".
Returns:
A single Level 1 market data quote and Greek data for one or more option symbols
as a Python object representation of the returned json.
get_market_quotes_strategies(self, variants, verbose='')
Definition:
Provides a calculated L1 market data quote for a single or many multi-leg
strategies.
Parameter:
- variants is a list of dictionary items.
- verbose level of verbosity represented by the number of characters in a string.
Defaults to empty string. Maximum verbosity is 2 or "vv".
Returns:
A calculated L1 market data quote for a single or many multi-leg strategies
as a Python object representation of the returned json.
get_markets(self, verbose='')
Description:
Provides market data.
Parameters:
- verbose level of verbosity represented by the number of characters in a string.
Defaults to empty string. Maximum verbosity is 2 or "vv".
Returns:
Information about supported markets as a Python object representation of
the returned json.
get_new_refresh_token(self, token, server_type, verbose='')
Description:
Obtains a new refresh token (and new access token) from the Authorization server.
You generally would not need to call this method, as it is potentially called by
Trader during initialization.
Trader will only call this method if the access token has expired.
Parameters:
- token the refresh token that is stored in the local file pointed to by rt_file.
- server_type should be "live" or "test" for your live Questrade account or
your test Questrade account, respectively.
- verbose level of verbosity represented by the number of characters in a string.
Defaults to empty string. Maximum verbosity is 1 or "v".
get_server_time(self, verbose='')
Description:
Provides the time from the Questrade API server.
Parameters:
- verbose level of verbosity represented by the number of characters in a string.
Defaults to empty string. Maximum verbosity is 2 or "vv".
Returns:
The time on the server as a tuple made of a simple datetime object,
as well as in the expected Python object representation of the returned json.
get_symbol_options(self, sid, verbose='')
Definition:
Provides symbol options data.
Parameter:
- sid Internal symbol identifier.
- verbose level of verbosity represented by the number of characters in a string.
Defaults to empty string. Maximum verbosity is 2 or "vv".
Returns:
An option chain for a particular underlying symbol as a Python object
representation of the returned json.
get_symbols_by_ids(self, ids, verbose='')
Definition:
Provides symbols data from symbol id(s).
Parameter:
- ids Internal symbol identifier(s). Could be a single numeric value or a string
of comma-seperated values (with no spaces).
- verbose level of verbosity represented by the number of characters in a string.
Defaults to empty string. Maximum verbosity is 2 or "vv".
Returns:
Detailed information about one or more symbol as a Python object representation
of the returned json.
get_symbols_by_names(self, names, verbose='')
Definition:
Provides symbols data from name(s).
Parameter:
- names is a string of names seperated by commas (with no spaces).
- verbose level of verbosity represented by the number of characters in a string.
Defaults to empty string. Maximum verbosity is 2 or "vv".
Returns:
Detailed information about one or more symbol as a Python object representation
of the returned json.
object_to_qdstr(self, dto, gmt=False)
Description:
Converts a datetime object to a Questrade datetime string.
Parameters:
- dto datetime object.
- gmt optional boolean indicating if datetime is Greenwich Mean Time.
Default value is False.
Returns:
The provided datetime object in Questrade API compatible string format.
Example: "2011-02-01T00:00:00-05:00".
If gmt is set to False, time will be in local time.
If gmt is True, the returned time will be considered as gmt time.
search_symbols(self, prefix, offset=0, verbose='')
Definition:
Provides symbol(s) data using several search criteria.
Parameters:
- prefix Prefix of a symbol or any word in the description.
- offset Offset in number of records from the beginning of a result set.
Default is not to offset.
- verbose level of verbosity represented by the number of characters in a string.
Defaults to empty string. Maximum verbosity is 2 or "vv".
Returns:
Symbol(s) data as a Python object representation of the returned json.
values_to_dobj(self, y, m, d, h=0, mi=0, s=0)
Description:
Helper method that builds a datetime object.
Parameters:
- y integer to be set as the year.
- m intiger to be set as the month.
- d integer to be set as the day.
- h optional integer to be set as the hour. Default value is 0.
- mi optional integer to be set as the minutes. Default value is 0.
- s optional integer to be set as the seconds. Default value is 0.
Returns:
A datetime object from the values provided as parameters.
values_to_qdstr(self, y, m, d, h=0, mi=0, s=0, gmt=False)
Description:
Helper method that builds a Questrade datetime string.
- y integer to be set as the year.
- m intiger to be set as the month.
- d integer to be set as the day.
- h optional integer to be set as the hour. Default value is 0.
- mi optional integer to be set as the minutes. Default value is 0.
- s optional integer to be set as the seconds. Default value is 0.
- gmt optional boolean indicating if datetime is Greenwich Mean Time.
Default value is False.
Returns:
The date time and timezone values provided as parameters in Questrade API
compatible string format.
Example: "2011-02-01T00:00:00-05:00".
If gmt is set to False, time will be in local time.
If gmt is True, the returned time will be considered as gmt time.
Example of Executable Module
Open a command line in the directory containing your logs, and run the module:
kwess_acb
(or)
python -m kwess.kwess_acb
To run the scrpit:
kwess_acb [-h] [-s SYMBOL [SYMBOL ...]] [-y CUT_OFF_YEAR] [-p PATH]
Computes the ACB (Average/Adjusted Cost Base) from kwess activity logs, and
prints profit/loss of Sell transactions.
options:
-h, --help show this help message and exit.
-s SYMBOL [SYMBOL ...], --symbol SYMBOL [SYMBOL ...]
ticker symbol(s). defaults to all.
-y CUT_OFF_YEAR, --cut_off_year CUT_OFF_YEAR
cut off year. defaults to the current year.
-p PATH, --path PATH path of the directory containing the logs.
defaults to the current directory.
Let me know if you have any questions: kaiyoux@gmail.com
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file kwess-0.2.3.tar.gz.
File metadata
- Download URL: kwess-0.2.3.tar.gz
- Upload date:
- Size: 32.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
79206b6ac8e8b913a62653f108b621d9e2d4ee7578b0ac7af6382311e2a07ca9
|
|
| MD5 |
611922eefd20b616f33ccd7ed835f176
|
|
| BLAKE2b-256 |
417adb321f60443398aa974a4522eb321da74b57ea67fe7e7597343f8ea07dc7
|
File details
Details for the file kwess-0.2.3-py3-none-any.whl.
File metadata
- Download URL: kwess-0.2.3-py3-none-any.whl
- Upload date:
- Size: 29.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d93ee9cfa5cd70c1d75b490a8ac526dc5145e66bdab45feaabb936ac986efe54
|
|
| MD5 |
0fceff71aac8b1f91ab3af4242d69a4b
|
|
| BLAKE2b-256 |
db184356a3767babe07e8bb4c933fa9a553dcc29e416904d5c4b1aec3c2e295f
|