Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Tehran Stock Exchange Source #909

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/source/readers/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@ Data Readers
tsp
world-bank
yahoo
tse
7 changes: 7 additions & 0 deletions docs/source/readers/tse.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Tehran Stock Exchange
------------------------------------

.. py:module:: pandas_datareader.tse
.. autoclass:: TSEReader
:members:
:inherited-members: read
29 changes: 29 additions & 0 deletions docs/source/remote_data.rst
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ Currently the following sources are supported:
- :ref:`Tiingo<remote_data.tiingo>`
- :ref:`World Bank<remote_data.wb>`
- :ref:`Yahoo Finance<remote_data.yahoo>`
- :ref:`Tehran Stock Exchange<remote_data.tse>`

It should be noted, that various sources support different kinds of data, so not all sources implement the same methods and the data elements returned might also differ.

Expand Down Expand Up @@ -762,3 +763,31 @@ The following endpoints are available:

dividends = web.DataReader('IBM', 'yahoo-dividends', start, end)
dividends.head()

.. _remote_data.tse:

Tehran Stock Exchange
=====================
An interface to structure the information provided by
`Tehran Stock Exchange <https://www.tsetmc.com/>`_

.. ipython:: python

import pandas_datareader.data as web
from datetime import datetime
start = datetime(2021, 1, 1)
end = dt.datetime.today()
f = web.DataReader("نوری", "tse", start, end)
f.head()

# Adjust prices
f = web.get_data_tse("نوری", start, end, adjust_price=True)
f.head()

# Resamle Close price weekly or monthly
f = web.get_data_tse("نوری", start, end, interval="m")
f.head()

# Multiple series:
multi = web.DataReader(["نوری", "برکت"], "tse", start, end)
multi.head()
2 changes: 2 additions & 0 deletions pandas_datareader/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
get_data_quandl,
get_data_stooq,
get_data_tiingo,
get_data_tse,
get_data_yahoo,
get_data_yahoo_actions,
get_iex_book,
Expand All @@ -40,6 +41,7 @@
"get_components_yahoo",
"get_data_enigma",
"get_data_famafrench",
"get_data_tse",
"get_data_yahoo",
"get_data_yahoo_actions",
"get_quote_yahoo",
Expand Down
48 changes: 48 additions & 0 deletions pandas_datareader/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
TiingoIEXHistoricalReader,
TiingoQuoteReader,
)
from pandas_datareader.tse import TSEReader
from pandas_datareader.yahoo.actions import YahooActionReader, YahooDivReader
from pandas_datareader.yahoo.components import _get_data as get_components_yahoo
from pandas_datareader.yahoo.daily import YahooDailyReader
Expand All @@ -46,6 +47,7 @@
"get_data_fred",
"get_data_moex",
"get_data_quandl",
"get_data_tse",
"get_data_yahoo",
"get_data_yahoo_actions",
"get_nasdaq_symbols",
Expand Down Expand Up @@ -270,6 +272,38 @@ def get_iex_book(*args, **kwargs):
return IEXDeep(*args, **kwargs).read()


def get_data_tse(*args, **kwargs):
"""
Tehran stock exchange daily data

Returns DataFrame of historical data from the Tehran Stock Exchange
open data service, over date range, start to end.

Parameters
----------
symbols : {int, str, List[str], List[int]}
The symbols can be persian symbol code or instrument id.
This argument can be obtained from tsetmc.com site.
start : string, int, date, datetime, Timestamp
Starting date. Parses many different kind of date
default value is 5 years ago
representations (e.g., 'JAN-01-2010', '1/1/10', 'Jan, 1, 1980')
end : string, int, date, datetime, Timestamp
Ending date
retry_count : int, default 3
Number of times to retry query request.
pause : float, default 0.1
Time, in seconds, of the pause between retries.
session : Session, default None
requests.sessions.Session instance to be used.
adjust_price : bool, default False
If True, adjusts all prices in hist_data ('Open', 'High', 'Low',
'Close') based on 'Adj Close' and 'Yesterday' price.
interval: string, d, w, m for daily, weekly, monthly
"""
return TSEReader(*args, **kwargs).read()


@deprecate_kwarg("access_key", "api_key")
def DataReader(
name,
Expand Down Expand Up @@ -360,6 +394,7 @@ def DataReader(
"av-intraday",
"econdb",
"naver",
"tse",
]

if data_source not in expected_source:
Expand Down Expand Up @@ -668,6 +703,19 @@ def DataReader(
session=session,
).read()

elif data_source == "tse":
return TSEReader(
symbols=name,
start=start,
end=end,
retry_count=retry_count,
pause=pause,
session=session,
adjust_price=False,
chunksize=10,
interval="d",
).read()

else:
msg = "data_source=%r is not implemented" % data_source
raise NotImplementedError(msg)
Expand Down
57 changes: 57 additions & 0 deletions pandas_datareader/tests/test_tse.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
from datetime import datetime

import pandas as pd
import pytest

from pandas_datareader import data as web

pytestmark = pytest.mark.stable


class TestTSE(object):
@property
def start(self):
return datetime(2021, 3, 1)

@property
def end(self):
return datetime(2021, 9, 15)

def test_tse(self):
df = web.DataReader("نوری", "tse", self.start, self.end)
assert df.index.name == "Date"
assert df.index[0] == pd.to_datetime(self.start)
assert df.index[-1] == pd.to_datetime(self.end)
assert len(df) == 123

def test_tse_int_symbol(self):
df = web.DataReader("19040514831923530", "tse", self.start, self.end)
assert df.index.name == "Date"
assert df.index[0] == pd.to_datetime(self.start)
assert df.index[-1] == pd.to_datetime(self.end)
assert len(df) == 123

def test_tse_multi(self):
names = ["خصدرا", "زاگرس"]
df = web.DataReader(names, "tse", self.start, self.end)
assert df.index.name == "Date"
assert df.index[0] == pd.to_datetime(self.start)
assert df.index[-1] == pd.to_datetime(self.end)
assert list(df.columns.get_level_values(1)[0 : len(names)]) == names
assert len(df) == 126

def test_tse_multi_bad_series(self):
names = ["NOTAREALSERIES", "نوری", "ALSOFAKE"]
with pytest.raises(Exception):
web.DataReader(names, data_source="tse")

def test_tse_raises_exception(self):
with pytest.raises(Exception):
web.DataReader("NON EXISTENT SERIES", "tse", self.start, self.end)

def test_tse_helper(self):
df = web.get_data_tse("نوری", self.start, self.end)
assert df.index.name == "Date"
assert df.index[0] == pd.to_datetime(self.start)
assert df.index[-1] == pd.to_datetime(self.end)
assert len(df) == 123
Loading