An open API service indexing awesome lists of open source software.

https://github.com/davidhintelmann/datareader_tmx

Get Stock Option Prices from TMX (Montreal Exchange)
https://github.com/davidhintelmann/datareader_tmx

montreal options python tmx

Last synced: 7 months ago
JSON representation

Get Stock Option Prices from TMX (Montreal Exchange)

Awesome Lists containing this project

README

          

If you are looking for the original repo please checkout `og` branch.

# Montreal Exchange (TMX)

The [Montreal Exchange](https://www.m-x.ca/accueil_en.php) is the oldest exchange in Canada and has a very important history to Canada's economy. Taken from Wikipedia,

>The Montreal Exchange, formerly the Montreal Stock Exchange (MSE), is a derivatives exchange, located in Montreal, Quebec, Canada that trades futures contracts and options on equities, indices, currencies, ETFs, energy and interest rates. Since 1965, it has been located in the Tour de la Bourse (Stock Exchange Tower), Montreal's third-tallest building. It is owned by the Toronto-based TMX Group.

This README file is to showcase the functionality of this small web scraping module. It can be used to get options prices, both calls and puts for index and ETF options, equity options, currency options, and weekly options.

These prices are then displayed in a Pandas Dataframe for further analysis. This could include simple plots for visualizing the data or creating machine learning model or neural network to predict future prices. One could also use [Black-Scholes](https://en.wikipedia.org/wiki/Black–Scholes_model) model to gain further insight.

---

# Requirements
1. Python **3.11.5**
2. Pandas **2.1.0** (older version will probably work)
3. Requests **2.31.0** (older version will probably work)
4. bs4 **4.12.2** (for BeautifulSoup)
- lxml **5.3.0** used with bs4 to process xml and html

---

We start by showing a list of options available from [TMX](https://m-x.ca/nego_liste_en.php). There is one parameter for the function `get_list()` and it can take one of four stings:

'Index'/'ETF', 'Equity', 'Currency', or 'Weekly'.

The webpage looks like: ![Options list from Montreal Exchance (TMX)](img/a.png)

```python
get_list('equity')
```




Name of underlying instrument
Option symbol
Underlying symbol




0
Aecon Group Inc.
ARE
ARE


1
AGF Management Ltd., Cl. B
AGF
AGF.B


2
Agnico Eagle Mines Limited
AEM
AEM


3
Air Canada
AC
AC


4
Alamos Gold Inc.
AGI
AGI


...
...
...
...


264
Wheaton Precious Metals Corp.
WPM
WPM


265
Whitecap Resources Inc.
WCP
WCP


266
Winpak Ltd.
WPK
WPK


267
WSP Global Inc.
WSP
WSP


268
Yamana Gold Inc.
YRI
YRI

269 rows × 3 columns


The above DataFrame that we get with `get_list('equity')` is from:
![Equity Options list from Montreal Exchance (TMX)](img/b.png)

Now we can grab stock prices for Air Canada (ticker symbol AC) so we can compare them to the stock options:

```python
get_stock('AC')
```




TICKER
Last price
Net change
Bid price
Ask price




0
AC
15.520
0.000
15.520
15.550

We can also input a list of stock symbols to get a Pandas DataFrame of said stocks:

```python
get_stock(['AC','ARE'])
```




TICKER
Last price
Net change
Bid price
Ask price




0
AC
15.520
0.000
15.520
15.550


1
ARE
14.220
0.100
14.200
14.250

Finally, we obtain the a Pandas Dataframe of TMX stock options for [Air Canada](https://m-x.ca/nego_cotes_en.php?symbol=AC*) which comes from:

![Equity Options list from Montreal Exchance (TMX)](img/c.png)

```python
get('AC')
```




Call
Bid price
Ask price
Last price
Impl. vol.
Open int.
Vol.
Strike
Put
Bid price_
Ask price_
Last price.1
Impl. vol_
Open int_
Vol_




0
Oct 23, 2020-W
2.05
2.20
2.20
86.5%
10
0
13.5
Oct 23, 2020-W
0.01
0.12
0.12
75.8%
17
0


1
Oct 23, 2020-W
1.57
1.77
1.77
79.0%
0
0
14.0
Oct 23, 2020-W
0.08
0.14
0.14
71.0%
30
0


2
Oct 23, 2020-W
1.12
1.24
1.24
62.5%
10
0
14.5
Oct 23, 2020-W
0.10
0.18
0.18
59.2%
23
10


3
Oct 23, 2020-W
0.73
0.84
0.84
57.0%
7
0
15.0
Oct 23, 2020-W
0.19
0.29
0.29
53.8%
57
7


4
Oct 23, 2020-W
0.44
0.54
0.54
56.0%
47
141
15.5
Oct 23, 2020-W
0.37
0.53
0.53
53.7%
46
1


...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...


153
Jan 20, 2023
3.55
7.35
7.35
76.4%
2
0
21.0
Jan 20, 2023
8.85
12.50
12.50
74.4%
0
0


154
Jan 20, 2023
3.30
7.20
7.20
76.3%
0
0
22.0
Jan 20, 2023
9.60
13.30
13.30
74.2%
0
0


155
Jan 20, 2023
3.10
7.00
7.00
76.2%
0
0
23.0
Jan 20, 2023
10.35
14.10
14.10
73.8%
0
0


156
Jan 20, 2023
2.84
6.80
6.80
75.6%
0
0
24.0
Jan 20, 2023
11.10
14.85
14.85
73.0%
0
0


157
Jan 20, 2023
3.15
5.00
5.00
69.3%
32
7
25.0
Jan 20, 2023
11.90
15.75
15.75
73.3%
0
0

158 rows × 15 columns


```python
import pandas as pd
import requests
from bs4 import BeautifulSoup
```

```python
"""
Get a list of options from https://m-x.ca/nego_liste_en.php
TMX website

Index and ETF options
Equity options
Currency options
Weekly options
"""
def get_list(market=str) -> pd.DataFrame:
tmx = "https://m-x.ca/nego_liste_en.php" # TMX website, where data is taken from

#check that parameter is of type string
is_str1 = isinstance(market, str)
if not is_str1:
raise TypeError("market parameter must be of type string")

try:
market = market.lower()
except Exception as e:
print(e)
else:
if market == 'index' or market == 'etf':
market = 0
elif market == 'equity':
market = 1
elif market == 'currency':
market = 2
elif market == 'weekly':
market = 3
else:
raise Exception("Did not enter market type, choose from Index or ETF, Equity, Currency, Weekly.")
df = pd.read_html(tmx)
return df[market]
```

```python
"""
Get options prices at predetermined dates from TMX website
Call/Puts
strike price
Bid/Ask spreads
open interest
implied volatility
volume
"""
def get(ticker_symbol=str) -> pd.DataFrame:
tmx = "https://m-x.ca/nego_cotes_en.php" # TMX website, where data is taken from

is_str1 = isinstance(ticker_symbol, str)
if not is_str1:
raise TypeError("ticker_symbol parameter must be of type string")

try:
ticker_symbol = ticker_symbol.upper()
except Exception as e:
print(e)
else:
url = tmx + '?symbol=' + ticker_symbol + '*'
df = pd.read_html(url)
df[0].rename(columns={'Bid price.1':'Bid price_', 'Ask price.1':'Ask price_', 'Last Price.1':'Last Price_',
'Impl. vol..1':'Impl. vol_', 'Open int..1':'Open int_', 'Vol..1':'Vol_'}, inplace=True)
return df[0].iloc[:-1] #do not include last row, rubbish information
```

```python
"""
Get stock price from TMX to compare to strike price
can accept string or list of strings
"""
def get_stock(ticker_symbol=str) -> pd.DataFrame:
tmx = "https://m-x.ca/nego_cotes_en.php" # TMX website, where data is taken from

#check that parameter is of type string
is_str1 = checktype(ticker_symbol)
if not is_str1:
raise TypeError("market parameter must be of type string")

#download stock price, remember it is 15 minutes delayed
try:
symbols = []
for n in ticker_symbol:
symbols.append(n.upper())

except Exception as e:
print(e)
else:
price_dict = {}
is_list = isinstance(ticker_symbol, list)
if is_list:
df_list = []
for m in symbols:
URL = tmx + '?symbol=' + m + '*'
response = requests.get(URL)
soup = BeautifulSoup(response.text, 'html.parser')
x = soup.find('div', class_ = 'quote-info', attrs = 'ul')
y = x.ul.text.split('\n')[1:-2]

price_dict['TICKER'] = m
for z in y:
key, value = z.split(':')
price_dict[key] = value
tmp_df = pd.DataFrame.from_dict(price_dict, orient='index').T
df_list.append(tmp_df)
return pd.concat(df_list, ignore_index=True)
else:
ticker_symbol = ticker_symbol.upper()
URL = tmx + '?symbol=' + ticker_symbol + '*'
response = requests.get(URL)
soup = BeautifulSoup(response.text, 'html.parser')
x = soup.find('div', class_ = 'quote-info', attrs = 'ul')
y = x.ul.text.split('\n')[1:-2]

price_dict['TICKER'] = ticker_symbol
for z in y:
key, value = z.split(':')
price_dict[key] = value
tmp_df = pd.DataFrame.from_dict(price_dict, orient='index').T
return tmp_df

```

```python
def checktype(obj):
return bool(obj) and all(isinstance(elem, str) for elem in obj)
```