diff --git a/.github/workflows/Push-nd-PR.yml b/.github/workflows/Push-nd-PR.yml new file mode 100644 index 0000000..4e78fcf --- /dev/null +++ b/.github/workflows/Push-nd-PR.yml @@ -0,0 +1,64 @@ +name: Python Pytest + +permissions: + contents: read + issues: read + checks: write + pull-requests: write + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +jobs: + Test: + + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: ["3.10", "3.11"] + + steps: + - uses: actions/checkout@v4 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v3 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + python -m pip install pylint pytest-cov + python setup.py install + + - name: Lint with pylint + run: | + STAT=$(pylint $(git ls-files '*.py') |grep -o "at.*(" | cut -d ' ' -f3) + echo $STAT + OUTPUT="Last pylint run status: ${OUTPUT}" + echo "## ${OUTPUT}" >> $GITHUB_STEP_SUMMARY + echo "MESSAGE=$OUTPUT" >> $GITHUB_ENV + + - name: Post pylint result to PR + if: github.event_name == 'pull_request' + uses: mshick/add-pr-comment@v1 + with: + message: ${{ env.MESSAGE }} + repo-token: ${{ secrets.GITHUB_TOKEN }} + repo-token-user-login: 'github-actions[bot]' + allow-repeats: false + + - name: Test with pytest + id: pytest + run: | + pytest tests/ --doctest-modules \ + --junitxml=junit/test-results.xml \ + --cov=com --cov-report=xml --cov-report=html + + - name: Publish Test Results + uses: EnricoMi/publish-unit-test-result-action/linux@v2 + with: + files: | + junit/test-results.xml diff --git a/.github/workflows/pylint.yml b/.github/workflows/pylint.yml deleted file mode 100644 index f83ce2a..0000000 --- a/.github/workflows/pylint.yml +++ /dev/null @@ -1,30 +0,0 @@ -name: Pylint - -on: - push: - paths: - - "nsedt/**" - -jobs: - build: - runs-on: ubuntu-latest - strategy: - matrix: - python-version: ["3.10"] - steps: - - uses: actions/checkout@v3 - - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v3 - with: - python-version: ${{ matrix.python-version }} - - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install pylint - pip install -r requirements.txt - - - name: Analysing the code with pylint - run: | - pylint $(git ls-files '*.py') diff --git a/README.md b/README.md index b4972f6..5a36c4b 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ Thank you for using Nsedt. Please feel free to send pull requests, comments, and `pip install -r requirements.txt` 3. Install locally `pip install . --upgrade` + --- ## Equity @@ -97,7 +98,6 @@ data["Date"] = pd.to_datetime(data["Date"],format='%d-%b-%Y') ```py from nsedt import derivatives as de - start_date = "24-04-2024" end_date = "25-04-2024" # date format "%d-%m-%Y" diff --git a/nsedt/derivatives/options.py b/nsedt/derivatives/options.py index dae891a..f09b357 100644 --- a/nsedt/derivatives/options.py +++ b/nsedt/derivatives/options.py @@ -7,7 +7,7 @@ from datetime import datetime from nsedt import utils from nsedt.resources import constants as cns -from nsedt.utils import data_format +from nsedt.utils import data_format, exceptions log = logging.getLogger("root") @@ -151,14 +151,18 @@ def get_historical_option_data( "symbol": symbol, "from": start_date, "to": end_date, - "instrumentType" : "OPTSTK", + "instrumentType": "OPTSTK", "optionType": option_type, - "expiryDate": expiry_date, + "expiryDate": datetime.strptime(expiry_date, "%d-%m-%Y").strftime("%d-%b-%Y"), "strikePrice": strike_price, - "year": year + "year": year, } url = base_url + event_api + urllib.parse.urlencode(params) data = utils.fetch_url(url, cookies, response_type="json") + + if data["data"] == []: + raise exceptions.DateStrikePriceOutofRange() + return data_format.derivaties_options( data, response_type=response_type, diff --git a/nsedt/resources/index_symbol.py b/nsedt/resources/index_symbol.py index e1e8889..ad2dd75 100644 --- a/nsedt/resources/index_symbol.py +++ b/nsedt/resources/index_symbol.py @@ -17,11 +17,31 @@ "derivatives": "FINNIFTY", "indices": "NIFTY FINANCIAL SERVICES", }, - {"keys": ["NIFTY NEXT 50"], "derivatives": "", "indices": "NIFTY NEXT 50"}, - {"keys": ["NIFTY MIDCAP 50"], "derivatives": "", "indices": "NIFTY MIDCAP 50"}, - {"keys": ["NIFTY MIDCAP 100"], "derivatives": "", "indices": "NIFTY MIDCAP 100"}, - {"keys": ["NIFTY MIDCAP 150"], "derivatives": "", "indices": "NIFTY MIDCAP 150"}, - {"keys": ["NIFTY SMALLCAP 50"], "derivatives": "", "indices": "NIFTY SMALLCAP 50"}, + { + "keys": ["NIFTY NEXT 50"], + "derivatives": "", + "indices": "NIFTY NEXT 50", + }, + { + "keys": ["NIFTY MIDCAP 50"], + "derivatives": "", + "indices": "NIFTY MIDCAP 50", + }, + { + "keys": ["NIFTY MIDCAP 100"], + "derivatives": "", + "indices": "NIFTY MIDCAP 100", + }, + { + "keys": ["NIFTY MIDCAP 150"], + "derivatives": "", + "indices": "NIFTY MIDCAP 150", + }, + { + "keys": ["NIFTY SMALLCAP 50"], + "derivatives": "", + "indices": "NIFTY SMALLCAP 50", + }, { "keys": ["NIFTY SMALLCAP 100"], "derivatives": "", @@ -37,8 +57,16 @@ "derivatives": "", "indices": "NIFTY MIDSMALLCAP 400", }, - {"keys": ["NIFTY 100"], "derivatives": "", "indices": "NIFTY 100"}, - {"keys": ["NIFTY 200"], "derivatives": "", "indices": "NIFTY 200"}, + { + "keys": ["NIFTY 100"], + "derivatives": "", + "indices": "NIFTY 100", + }, + { + "keys": ["NIFTY 200"], + "derivatives": "", + "indices": "NIFTY 200", + }, { "keys": ["NIFTY500 MULTICAP 50:25:25"], "derivatives": "", @@ -64,20 +92,56 @@ "derivatives": "", "indices": "NIFTY MICROCAP 250", }, - {"keys": ["NIFTY AUTO"], "derivatives": "", "indices": "NIFTY AUTO"}, - {"keys": ["NIFTY ENERGY"], "derivatives": "", "indices": "NIFTY ENERGY"}, + { + "keys": ["NIFTY AUTO"], + "derivatives": "", + "indices": "NIFTY AUTO", + }, + { + "keys": ["NIFTY ENERGY"], + "derivatives": "", + "indices": "NIFTY ENERGY", + }, { "keys": ["NIFTY FINANCIAL SERVICES 25/50"], "derivatives": "", "indices": "NIFTY FINANCIAL SERVICES 25/50", }, - {"keys": ["NIFTY FMCG"], "derivatives": "", "indices": "NIFTY FMCG"}, - {"keys": ["NIFTY IT"], "derivatives": "", "indices": "NIFTY IT"}, - {"keys": ["NIFTY MEDIA"], "derivatives": "", "indices": "NIFTY MEDIA"}, - {"keys": ["NIFTY METAL"], "derivatives": "", "indices": "NIFTY METAL"}, - {"keys": ["NIFTY PHARMA"], "derivatives": "", "indices": "NIFTY PHARMA"}, - {"keys": ["NIFTY PSU BANK"], "derivatives": "", "indices": "NIFTY PSU BANK"}, - {"keys": ["NIFTY REALTY"], "derivatives": "", "indices": "NIFTY REALTY"}, + { + "keys": ["NIFTY FMCG"], + "derivatives": "", + "indices": "NIFTY FMCG", + }, + { + "keys": ["NIFTY IT"], + "derivatives": "", + "indices": "NIFTY IT", + }, + { + "keys": ["NIFTY MEDIA"], + "derivatives": "", + "indices": "NIFTY MEDIA", + }, + { + "keys": ["NIFTY METAL"], + "derivatives": "", + "indices": "NIFTY METAL", + }, + { + "keys": ["NIFTY PHARMA"], + "derivatives": "", + "indices": "NIFTY PHARMA", + }, + { + "keys": ["NIFTY PSU BANK"], + "derivatives": "", + "indices": "NIFTY PSU BANK", + }, + { + "keys": ["NIFTY REALTY"], + "derivatives": "", + "indices": "NIFTY REALTY", + }, { "keys": ["NIFTY PRIVATE BANK"], "derivatives": "", @@ -103,7 +167,11 @@ "derivatives": "", "indices": "NIFTY DIVIDEND OPPORTUNITIES 50", }, - {"keys": ["NIFTY50 VALUE 20"], "derivatives": "", "indices": "NIFTY50 VALUE 20"}, + { + "keys": ["NIFTY50 VALUE 20"], + "derivatives": "", + "indices": "NIFTY50 VALUE 20", + }, { "keys": ["NIFTY100 QUALITY 30"], "derivatives": "", @@ -124,7 +192,11 @@ "derivatives": "", "indices": "NIFTY100 LOW VOLATILITY 30", }, - {"keys": ["NIFTY ALPHA 50"], "derivatives": "", "indices": "NIFTY ALPHA 50"}, + { + "keys": ["NIFTY ALPHA 50"], + "derivatives": "", + "indices": "NIFTY ALPHA 50", + }, { "keys": ["NIFTY200 QUALITY 30"], "derivatives": "", @@ -145,25 +217,41 @@ "derivatives": "", "indices": "NIFTY MIDCAP150 QUALITY 50", }, - {"keys": ["NIFTY COMMODITIES"], "derivatives": "", "indices": "NIFTY COMMODITIES"}, + { + "keys": ["NIFTY COMMODITIES"], + "derivatives": "", + "indices": "NIFTY COMMODITIES", + }, { "keys": ["NIFTY INDIA CONSUMPTION"], "derivatives": "", "indices": "NIFTY INDIA CONSUMPTION", }, - {"keys": ["NIFTY CPSE"], "derivatives": "", "indices": "NIFTY CPSE"}, + { + "keys": ["NIFTY CPSE"], + "derivatives": "", + "indices": "NIFTY CPSE", + }, { "keys": ["NIFTY INFRASTRUCTURE"], "derivatives": "", "indices": "NIFTY INFRASTRUCTURE", }, - {"keys": ["NIFTY MNC"], "derivatives": "", "indices": "NIFTY MNC"}, + { + "keys": ["NIFTY MNC"], + "derivatives": "", + "indices": "NIFTY MNC", + }, { "keys": ["NIFTY GROWTH SECTORS 15"], "derivatives": "", "indices": "NIFTY GROWTH SECTORS 15", }, - {"keys": ["NIFTY PSE"], "derivatives": "", "indices": "NIFTY PSE"}, + { + "keys": ["NIFTY PSE"], + "derivatives": "", + "indices": "NIFTY PSE", + }, { "keys": ["NIFTY SERVICES SECTOR"], "derivatives": "", @@ -184,7 +272,11 @@ "derivatives": "", "indices": "NIFTY INDIA DIGITAL", }, - {"keys": ["NIFTY100 ESG"], "derivatives": "", "indices": "NIFTY100 ESG"}, + { + "keys": ["NIFTY100 ESG"], + "derivatives": "", + "indices": "NIFTY100 ESG", + }, { "keys": ["NIFTY INDIA MANUFACTURING"], "derivatives": "", diff --git a/nsedt/utils/exceptions.py b/nsedt/utils/exceptions.py new file mode 100644 index 0000000..7678830 --- /dev/null +++ b/nsedt/utils/exceptions.py @@ -0,0 +1,38 @@ +"""_summary_ + +Returns: + _type_: _description_ +""" + + +class MissingEnvValue(BaseException): + """_summary_ + + Args: + BaseException (_type_): _description_ + """ + + def __init__(self, message: str): + self.message = message + + def __str__(self): + return f""" ----[ERROR]---- +================================================================================================= +{self.message} +================================================================================================= +""" + + +class DateStrikePriceOutofRange(BaseException): + """_summary_ + + Args: + BaseException (_type_): _description_ + """ + + def __str__(self): + return """ ----[ERROR]---- +================================================================================================= +Either Date of strike Price is out of range for NSE (No data found) +================================================================================================= +""" diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_derivatives_futures.py b/tests/test_derivatives_futures.py new file mode 100644 index 0000000..5b0940d --- /dev/null +++ b/tests/test_derivatives_futures.py @@ -0,0 +1,53 @@ +""" + Test case for nsedt.indices +""" + +from typing import List +import pandas as pd + +from nsedt.derivatives import futures as fut + +START_DATE = "01-01-2024" +END_DATE = "10-01-2024" +SYMBOL = "NIFTY" + + +def test_get_future_price(): + """ + Test the get_price function from nsedt.derivatives.futures module. + """ + + data = fut.get_future_price( + start_date=START_DATE, + end_date=END_DATE, + expiry_date="25-01-2024", + symbol=SYMBOL, + ) + assert isinstance(data, pd.DataFrame) + assert len(data) == 8 + assert list(data.columns) == [ + "Expiry Date", + "Open Price", + "High Price", + "Low Price", + "Close Price", + "FH_PREV_CLS", + "FH_SETTLE_PRICE", + "FH_TOT_TRADED_QTY", + "FH_TOT_TRADED_VAL", + "FH_OPEN_INT", + "Change in OI", + "Date", + "FH_UNDERLYING_VALUE", + ] + + +def test_get_future_expdate(): + """ + Test the get_future_expdate function from nsedt.derivatives.futures module. + """ + data = fut.get_future_expdate( + symbol=SYMBOL, + ) + assert isinstance(data, List) + assert len(data) == 3 diff --git a/tests/test_derivatives_options.py b/tests/test_derivatives_options.py new file mode 100644 index 0000000..45c7801 --- /dev/null +++ b/tests/test_derivatives_options.py @@ -0,0 +1,87 @@ +""" + Test case for nsedt.derivatives.options +""" + +from typing import List +import pandas as pd +import pytest +from nsedt.derivatives import options as opt + +START_DATE = "01-01-2024" +END_DATE = "10-01-2024" +SYMBOL = "TCS" + + +def test_get_option_chain(): + """ + Test the get_option_chain function from nsedt.derivatives.options module. + """ + + expiry_date = opt.get_option_chain_expdate(SYMBOL)[0] + data = opt.get_option_chain(SYMBOL, expiry_date=expiry_date) + assert isinstance(data, pd.DataFrame) + assert len(data) > 10 + assert list(data.columns) == [ + "strikePrice", + "expiryDate", + "PE.underlying", + "PE.openInterest", + "PE.changeinOpenInterest", + "PE.pchangeinOpenInterest", + "PE.totalTradedVolume", + "PE.impliedVolatility", + "PE.lastPrice", + "PE.change", + "PE.pChange", + "PE.totalBuyQuantity", + "PE.totalSellQuantity", + "PE.bidQty", + "PE.bidprice", + "PE.askQty", + "PE.askPrice", + "PE.underlyingValue", + "CE.underlying", + "CE.openInterest", + "CE.changeinOpenInterest", + "CE.pchangeinOpenInterest", + "CE.totalTradedVolume", + "CE.impliedVolatility", + "CE.lastPrice", + "CE.change", + "CE.pChange", + "CE.totalBuyQuantity", + "CE.totalSellQuantity", + "CE.bidQty", + "CE.bidprice", + "CE.askQty", + "CE.askPrice", + "CE.underlyingValue", + ] + assert data.loc[0, "PE.underlying"] == SYMBOL + + +def test_get_option_chain_expdate(): + """ + Test the get_option_chain_expdate function from nsedt.derivatives.options module. + """ + + data = opt.get_option_chain_expdate(SYMBOL) + assert isinstance(data, List) + assert len(data) > 1 + + +@pytest.mark.skip("Need to Fix code") +def test_get_historical_option_data(): + """ + Test the get_historical_option_data function from nsedt.derivatives.options module. + """ + data = opt.get_historical_option_data( + symbol=SYMBOL, + start_date=START_DATE, + end_date=END_DATE, + option_type="CE", + strike_price="3300", + year=2024, + expiry_date="28-03-2024", + ) + assert isinstance(data, pd.DataFrame) diff --git a/tests/test_equity.py b/tests/test_equity.py new file mode 100644 index 0000000..e7a4955 --- /dev/null +++ b/tests/test_equity.py @@ -0,0 +1,116 @@ +""" + Test case for nsedt.equity +""" +from typing import Dict, List +import pandas as pd + +from nsedt import equity as eq + +START_DATE = "01-01-2024" +END_DATE = "10-01-2024" +SYMBOL = "TCS" + +def test_get_price(): + """ + Test the get_price function from nsedt.equity module. + """ + + data = eq.get_price(START_DATE, END_DATE, SYMBOL) + + # Assert expected data structure and content + assert isinstance(data, pd.DataFrame) + assert len(data) == 8 + assert list(data.columns) == [ + "Date", + "Open Price", + "High Price", + "Low Price", + "Close Price", + "Prev Close Price", + "Last Traded Price", + "Total Traded Quantity", + "Total Traded Value", + "52 Week High Price", + "52 Week Low Price", + "VWAP", + "Deliverable Volume", + "Deliverable Percent", + "Series", + ] + assert data.loc[0, "Open Price"] == 3790.0 + assert data.loc[3, "Close Price"] == 3666.8 + + +def test_get_event(): + """ + Test the get_event function from nsedt.equity module. + """ + + data = eq.get_event(START_DATE, END_DATE) + + # Assert expected data structure and content + assert isinstance(data, pd.DataFrame) + assert len(data) == 39 + assert list(data.columns) == ["symbol", "company", "purpose", "bm_desc", "date"] + assert data.loc[0, "company"] == 'Gensol Engineering Limited' + assert data.loc[3, "date"] == '03-Jan-2024' + + +def test_get_companyinfo(): + """ + Test the get_companyinfo function from nsedt.equity module. + """ + + data = eq.get_companyinfo(SYMBOL,response_type="json") + + # Assert expected data structure and content + assert isinstance(data, Dict) + assert len(data) == 7 + assert list(data.keys()) == ['info', + 'metadata', + 'securityInfo', + 'sddDetails', + 'priceInfo', + 'industryInfo', + 'preOpenMarket', + ] + assert data['info']['companyName'] == 'Tata Consultancy Services Limited' + assert data['industryInfo']['sector'] == 'Information Technology' + + +def test_get_symbols_list(): + """ + Test the get_SYMBOLs_list function from nsedt.equity module. + """ + + data = eq.get_symbols_list() + + # Assert expected data structure and content + assert isinstance(data, List) + assert len(data) > 1000 + assert SYMBOL in data + + +def test_get_asm_list(): + """ + Test the get_asm_list function from nsedt.equity module. + """ + + data = eq.get_asm_list(asm_type = "shortterm") + + # Assert expected data structure and content + assert isinstance(data, List) + assert len(data) > 1 + + +def test_get_chartdatat(): + """ + Test the get_chartdata function from nsedt.equity module. + """ + + data = eq.get_chartdata("TCS") + + # Assert expected data structure and content + assert isinstance(data, pd.DataFrame) + assert len(data) > 1 + assert list(data.columns) == ['timestamp_milliseconds', 'price', 'datetime'] diff --git a/tests/test_indices.py b/tests/test_indices.py new file mode 100644 index 0000000..4a1701b --- /dev/null +++ b/tests/test_indices.py @@ -0,0 +1,30 @@ +""" + Test case for nsedt.indices +""" + +import pandas as pd + +from nsedt import indices as ind + +START_DATE = "01-01-2024" +END_DATE = "10-01-2024" +SYMBOL = "NIFTY" + + +def test_get_price(): + """ + Test the get_price function from nsedt.equity module. + """ + + data = ind.get_price(start_date=START_DATE, end_date=END_DATE, symbol="NIFTY") + assert isinstance(data, pd.DataFrame) + assert len(data) == 8 + assert list(data.columns) == [ + "Open Price", + "High Price", + "Close Price", + "Low Price", + "Date", + ] + assert data.loc[0, "Open Price"] == 21727.75 + assert data.loc[3, "Close Price"] == 21658.6