freetrade

API for Freetrade app


Keywords
Freetrade, API, stock
License
MIT
Install
pip install freetrade==0.0.6

Documentation

FreeTrade API

This is an attempt to make an unofficial Python package for FreeTrade. There is no official API released, yet. FreeTrade is a zero-fee UK-regulated stockbroker.

What is supported

  • Find list of tradable securities with information on the asset class, market, currency, country.
  • Create a list of tickers for Trading View's watch list.
  • Historical prices
  • Logging into Freetrade account and saving the session into ft-session.json file.

Install

Install through pip package manger:

pip install freetrade

Alternatively, for developing this package:

conda create -n myenv python=3.7
conda activate myenv
pip install -r requirements.txt

Prerequisites

Before running this, it is necessary to set the API keys. Edit ft-keys.json to include the necessary API keys. These keys can be found using a tool, which can extract StringCare secrets, e.g. DeStringCare.

API

Creating ft FreeTrade object

Without authentication

from freetrade import FreeTrade

ft = FreeTrade()

The only thing which will work is Index class, i.e. getting the list of supported stock tickers.

With authentication

from freetrade import FreeTrade

email = '...'  # Email to use for the login
ft = FreeTrade(email)

By default when creating the object, it will try to load an older authenticated session from ft-session.json file. Otherwise it logs in again, and requests a one time password (OTP), which is sent to the email.

The code parses OTP from the standard user input. Alternatively specify otp_parser parameter in FreeTrade object to a function which can fetch the email and parse the OTP itself.

Index - no authentication needed

Get assets

assets = ft.index.get_assets()

Returns a dictionary of different categories, which have subcategories. These subcategories contain a list of stock assets.

  • currency
    • GBP / USD: list of assets
  • exchange
    • XLON / XNYS / XNAS: list of assets
  • asset_class
    • ETF / EQUITY / ADR: list of assets
  • country_of_incorporation
    • IE / GB / US / KY / ... : list of assets
  • all: list of assets

Sample asset for an ETF LSE:ERNU:

{
    "asset_class": "ETF",
    "symbol": "ERNU",
    "isin": "IE00BCRY6227",
    "exchange": "XLON",
    "currency": "GBP",
    "country_of_incorporation": "IE",
    "long_title": "iShares $ Ultrashort Bond UCITS ETF (Dist.)",
    "short_title": "$ Ultrashort",
    "subtitle": "Very short maturity $ debt",
    "logo_4x": "//a.storyblok.com/f/41481/640x640/7ec0a292de/ishares-symbol-4x.png",
    "isa_eligible": true,
    "coming_soon": false,
    "required_version": "1.0",
    "objectID": "IE00BCRY6227",
    ...
}

Get tickers

tickers = ft.index.get_tickers()

Returns a dictionary, where:

  • key is an exchange symbol FreeTrade uses, and
  • value is a list of ticker symbols
tickers = {
    'XLON': ['ERNU', 'III', '3IN', ...],
    'XNYS': ['MMM', 'ABBV', 'BABA', ...],
    'XNAS': ['ATVI', 'ADBE', 'AMD', 'GOOGL', 'AMZN', ...]
}

Get list of tickers for Trading View watch list

tickers_union = ft.index.get_tradingview_tickers(join_exchanges=True)

Returns a string formatted for importing into Trading View watch list.

With join_exchanges = True:

tickers_union = 'LSE:ERNU,LSE:III,LSE:3IN,LSE:ABF,LSE:ACA,LSE:ADM,...'

Default (when join_exchanges = False):

tickers_union = {
    'XLON': 'LSE:ERNU,LSE:III,LSE:3IN,LSE:ABF,LSE:ACA,LSE:ADM,...',
    'XNYS': 'NYSE:MMM,NYSE:ABBV,NYSE:BABA,NYSE:AXP,NYSE:APA,NYSE:T,...',
    'XNAS': 'NASDAQ:ATVI,NASDAQ:ADBE,NASDAQ:AMD,NASDAQ:GOOGL,NASDAQ:AMZN,...'
}

API - requires authentication

Ticker history

Assuming ft object is created, here is how one month of historical price for a stock.

prices = ft.api.get_ticker_history('TSLA', 'XNAS')

for history_date, price in prices.items():
    print(f'{history_date}: ${price:.2f}')

Finding the address for a post code

postcode = 'E15JL'
address = ft.api.get_address_by_postcode(postcode)

Returns a list of addresses, e.g. sample address:

[{
    "summaryline": "Freetrade, 68-80 Hanbury Street, London, Greater London, E1 5JL",
    "organisation": "Freetrade",
    "number": "68-80",
    "premise": "68-80",
    "street": "Hanbury Street",
    "posttown": "London",
    "county": "Greater London",
    "postcode": "E1 5JL"
}]

Verifying bank number

bank = ft.api.validate_bank('308012', '15887060')

Returns a lot of information on the account number, e.g. sample values:

{
    "result": "VALID",
    "sortcode": "308012",
    "bicbank": "LOYDGB21",
    "bankname": "CITY OFFICE (308012)",
    "owningbank": "LLOYDS BANK PLC",
    "chapssrbicbank": "LOYDGB2L",
    "chapssrbicbr": "XXX",
    ...
}

Get price history

tesla = ft.api.get_ticker_history('TSLA', 'XNAS', duration='1m')
national_grid = ft.api.get_ticker_history('NG.', 'XLON', duration='1m')

The possible duration values, where 1m is default:

  • 5y, 2y, 1y, ytd, 6m, 3m, 1m, 1d

Returns an OrderedDict of data points (date, adjusted closing price) sorted by date in ascending order.

Sample output:

tesla = OrderedDict([
    ('2019-04-04', 267.78),
    ('2019-04-05', 274.96),
    ('2019-04-08', 273.2),
    ('2019-04-09', 272.31),
    ('2019-04-10', 276.06),
    ...
])

Notes:

  • use Quandl for UK securities;
  • uses IEXTrading for other securities.

DataStore - requires authentication

Download or update historical prices

ft.datastore.update_historical_prices()

Saves the adjusted historical closing prices for the assets into history directory. If it does not exist, it is created.

The file name is the ticker's symbol, and each the prices are saved in ascending order.

Sample in history/TSLA.csv:

2014-05-05,216.61
2014-05-06,207.28
2014-05-07,201.35
2014-05-08,178.59
2014-05-09,182.26
2014-05-12,184.67
2014-05-13,190.16
...

Load the historical data as pd.DataFrame

This function loads the historical data from history directory.

Note that some assets have missing prices as they were not traded during that day, thus they show up as nan.

df = ft.datastore.load_historical_data_as_dataframe()
print(df.head(), df.shape)

Sample output:

               CSCO          SVT  ...          WTB          NXT
Date                              ...                          
2014-05-05  19.5875  1486.452691  ...  3650.414898  5184.507159
2014-05-06  19.3870  1489.696450  ...  3659.383977  5137.446580
2014-05-07  19.5150  1509.159006  ...  3645.033451  5094.307715
2014-05-08  19.6413  1510.780885  ...  3677.322133  5082.542570
2014-05-09  19.6430  1512.402765  ...  3676.425226  5070.777425

[5 rows x 341 columns] (1305, 341)

Anything else?

  • Feel free to make a GitHub issue, if you find any issues or have enhancement ideas.

  • Pull requests are welcome, if you have made improvements to this code.