From 4e840effed807d440ec09386ecf1ef7eafb22c4c Mon Sep 17 00:00:00 2001 From: Debasish Pal <48341250+debpal@users.noreply.github.com> Date: Mon, 30 Sep 2024 19:05:45 +0300 Subject: [PATCH] major update --- .github/workflows/linting.yml | 1 - .github/workflows/testing.yml | 2 +- .github/workflows/typing.yml | 2 +- .gitignore | 1 + .readthedocs.yaml | 2 +- BharatFinTrack/__init__.py | 8 +- BharatFinTrack/core.py | 140 ++++++++++++++ BharatFinTrack/data/equity_indices.xlsx | Bin 0 -> 24385 bytes BharatFinTrack/nse_product.py | 221 +++++++++++++++++++++ BharatFinTrack/nse_track.py | 200 ------------------- BharatFinTrack/nse_tri.py | 166 ++++++++++++++++ MANIFEST.in | 3 + README.md | 60 ++++-- docs/BharatFinTrack.rst | 2 +- docs/changelog.rst | 29 ++- docs/conf.py | 3 +- docs/data_download.rst | 45 +++++ docs/index.rst | 17 +- docs/installation.rst | 41 +++- docs/introduction.rst | 13 ++ docs/modules.rst | 7 +- docs/quickstart.rst | 93 +++++++++ docs/requirements-docs.txt | 7 + docs/requirements.txt | 3 - docs/submodules.rst | 6 +- pyproject.toml | 22 ++- requirements-gh-action.txt | 6 + requirements-mypy.txt | 2 + tests/test_bharatfintrack.py | 243 ++++++++++++++++++++++++ tests/test_nse_track.py | 55 ------ 30 files changed, 1079 insertions(+), 321 deletions(-) create mode 100644 BharatFinTrack/core.py create mode 100644 BharatFinTrack/data/equity_indices.xlsx create mode 100644 BharatFinTrack/nse_product.py delete mode 100644 BharatFinTrack/nse_track.py create mode 100644 BharatFinTrack/nse_tri.py create mode 100644 MANIFEST.in create mode 100644 docs/data_download.rst create mode 100644 docs/introduction.rst create mode 100644 docs/quickstart.rst create mode 100644 docs/requirements-docs.txt delete mode 100644 docs/requirements.txt create mode 100644 requirements-gh-action.txt create mode 100644 requirements-mypy.txt create mode 100644 tests/test_bharatfintrack.py delete mode 100644 tests/test_nse_track.py diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index 8227d51..21e7051 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -35,5 +35,4 @@ jobs: - name: Lint with flake8 run: | - flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics \ No newline at end of file diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index d70f932..beb9d3f 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -32,7 +32,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - python -m pip install pytest pytest-cov # Install pytest and pytest-cov for coverage + python -m pip install -r requirements-gh-action.txt # Install dependencies - name: Run tests with pytest run: | diff --git a/.github/workflows/typing.yml b/.github/workflows/typing.yml index 8cde7c9..55d0ce2 100644 --- a/.github/workflows/typing.yml +++ b/.github/workflows/typing.yml @@ -31,7 +31,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - python -m pip install mypy + python -m pip install -r requirements-mypy.txt # Install dependencies - name: Type check with mypy run: | diff --git a/.gitignore b/.gitignore index 82f9275..d59f23c 100644 --- a/.gitignore +++ b/.gitignore @@ -50,6 +50,7 @@ coverage.xml .hypothesis/ .pytest_cache/ cover/ +tox.ini # Translations *.mo diff --git a/.readthedocs.yaml b/.readthedocs.yaml index dfc1dbf..65bcc60 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -7,7 +7,7 @@ build: python: install: - - requirements: docs/requirements.txt + - requirements: docs/requirements-docs.txt sphinx: configuration: docs/conf.py diff --git a/BharatFinTrack/__init__.py b/BharatFinTrack/__init__.py index d80d89a..a8916df 100644 --- a/BharatFinTrack/__init__.py +++ b/BharatFinTrack/__init__.py @@ -1,9 +1,11 @@ -from .nse_track import NSETrack +from .nse_product import NSEProduct +from .nse_tri import NSETRI __all__ = [ - 'NSETrack' + 'NSEProduct', + 'NSETRI' ] -__version__ = '0.0.3' +__version__ = '0.1.0' diff --git a/BharatFinTrack/core.py b/BharatFinTrack/core.py new file mode 100644 index 0000000..6fd7e08 --- /dev/null +++ b/BharatFinTrack/core.py @@ -0,0 +1,140 @@ +import os +import json +import typing +import datetime +import pandas +import requests + + +class Core: + + ''' + Core functionality of :mod:`BharatFinTrack` module. + ''' + + def _excel_file_extension( + self, + file_path: str + ) -> str: + + ''' + Returns the extension of an Excel file. + + Parameters + ---------- + file_path : str + Path of the Excel file. + + Returns + ------- + str + Extension of the Excel file. + ''' + + output = os.path.splitext(file_path)[-1] + + return output + + def string_to_date( + self, + date_string: str + ) -> datetime.date: + + ''' + Converts a date string is in format 'DD-MMM-YYYY' to a `datetime.date` object. + + Parameters + ---------- + date_string : str + Date string in the format 'DD-MMM-YYYY'. + + Returns + ------- + datetime.date + A `datetime.date` object corresponding to the input date string. + ''' + + output = datetime.datetime.strptime(date_string, '%d-%b-%Y').date() + + return output + + @property + def default_http_headers( + self, + ) -> dict[str, str]: + + ''' + Returns the default http headers to be used for the web requests. + ''' + + output = { + 'Content-Type': 'application/json; charset=UTF-8', + 'Accept': 'application/json, text/javascript, */*; q=0.01', + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', + 'Origin': 'https://www.niftyindices.com', + 'Accept-Encoding': 'gzip, deflate, br, zstd', + 'Connection': 'keep-alive', + 'X-Requested-With': 'XMLHttpRequest' + } + + return output + + @property + def url_nse_index_tri_data( + self, + ) -> str: + + ''' + Returns the url to access TRI (Total Return Index) data of NSE equity indices. + ''' + + output = 'https://www.niftyindices.com/Backpage.aspx/getTotalReturnIndexString' + + return output + + def _download_nse_tri( + self, + index_api: str, + start_date: str, + end_date: str, + index: str, + http_headers: typing.Optional[dict[str, str]] = None + ) -> pandas.DataFrame: + + ''' + Helper method for the :meth:`NSETRI.download_historical_daily_data`. + ''' + + # payloads + parameters = { + 'name': index_api, + 'startDate': start_date, + 'endDate': end_date, + 'indexName': index + } + payload = json.dumps( + { + 'cinfo': json.dumps(parameters) + } + ) + + # web request headers + headers = self.default_http_headers if http_headers is None else http_headers + + # sent web requets + response = requests.post( + url=self.url_nse_index_tri_data, + headers=headers, + data=payload + ) + response_data = response.json() + records = json.loads(response_data['d']) + df = pandas.DataFrame.from_records(records) + df = df.iloc[:, -2:][::-1].reset_index(drop=True) + df['Date'] = df['Date'].apply( + lambda x: datetime.datetime.strptime(x, '%d %b %Y').date() + ) + df = df.rename(columns={'TotalReturnsIndex': 'Close'}) + df['Close'] = df['Close'].astype(float) + + return df diff --git a/BharatFinTrack/data/equity_indices.xlsx b/BharatFinTrack/data/equity_indices.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..27746f424dbb42aac1361eeaa3b8143f9b03fa76 GIT binary patch literal 24385 zcmeIaWmH|uwl#_e4esvl?oM!mYjAgW3GVLh?hq_UaCbs*cXzi(vd?)rhqLc(`@J8x z-LHLn{#c7O*R0N5V^)pPt46Q!Q34nQ2>=WL8~^|SAAsoa<2N5b005$Q004*p;6Unv zR+jb#miAf-F4hKipJ<#d%<*zSfXK1{fL^cv`}n`u0>g>}mYsBPt;+knLTyUje5i`Z z-hzpGp&(BHh_KxR)zo8rYbTua9~F^9;Y7D$$f|d!5qG2t8;S%|1(Y(1YVbpMK_ba6~%)vXCk<-=W%cpa|p{fk~RD^V< zmn2$wUYzpToHZ4e!6~6#&es%r;;5xvWkg(D6ZO$GUthmWG(-8pv_z8ZL?V__H`~_o z3O6PIGg9jP{8nv9w)`bvTrbe)5{9b|Iz2Q1cuYb323s()Gq%aP(m2XoI;yZf%=$Lp zY|XhN(@!@YnS^LCVp^cC%E)esp>m#0blB{yQa8R>3n{ZXU*vi%?N8PsQ)PSA4~7Ly zz2I*}v5%l8Y~1iUj%kGYo_P20M)9J~T<_t->E693nydlgy0Jp%howiQ_>2QrxUhK$ z^2@9Reu71L`&3Zv@JEmRgMTXJFW7gMR z_woV^@bTY;pOW$lCL8Z>UHR9*&3MJ(bD{U{d>s%Up!9#<)@d$NXc~3K?j_O zJ_h#ROfN;j2}n5ci#FpcczzaJgsltDCBj_#Mv4WefZ+@L!K>Btad2UYD}28n|9YLN zEEEBWld#^YJRtGj#^D_WiEV<2P1#yEyyNuM^mXzFaThYj)<}xd#-ePAffYiLsWYK! zxG@@K3<$)0tN;}5WN)=zDb;1&+X}#G0r{iyfT{-8to_)rRIizYf;|}CAa=>a$z3ip0<{Hr?*MR{X(lPcW|TMhyjEq(L$3!&6+h)?d+(rNv21WX9G3}YYqh_kM| z)V?sC4W+wuvqE&0_MZ;;gyI%0zechD93-O+j&*Us006iU006MBmT@+xb+WQG)3vfP z`x)Evlq@1k*pQyv2AjBYf*26$5V-86 zxZFCvS+R5yuuKpzhsGl-fy)<<_cl;uGGH&Z6dHi6D)So-_Q}^!S0qOlD~Y3zH%ic3 zXp2YG%u2wInz0U=4v|NJP}?c{NFA(?F1zX(e_pdcYwHU0NqVz@MvCGbfh>V*W4|0< zSVY?Q!2zF0)e!C)$E{bhb0!eCUdQ??srTNxEPJ7xf^NR$=XulgwjkUElwMr9s&B&` z4w4nba|s6+IIS_yq^;+X8qb{Q^c#ye~Pz*N@F@AF#m@ zQ5lUFCR>n16{L$OOE$iSU!gUv(ZwwWO19{1=ryCkU`#cR+6_sV4XCOlBa|;fT?;4W zb9V#TnMq1KfMtYJZJH~@9(ZhE_mvD{DT?{>tff^q)JB|0mY&uS!Th4uKmaK@GblyF zar`BUIh#Wng{Ty!sFgz$XP*Xf`O z{3EeWte&%hk;OZ;*|ksK0S^$*{A)j5RgkqZU01eSCr6*ahKUKx8?0}{F|h*aUxCp%*Hd{Kz9x|mkTEr9V3@#EA3-w{E|dm}Gc#VI z2QEgmcFZ2bU{8hHn16LPPTiHv0bvn_WelE3T!O;{g(BO7vQ%J!02kqjoERj&;xwssjt`m-+i>iEt&e!!TFy+dAu9&2>;4UZLqN%*STE3@D7{< zLsg21@#*Y{6TBQb;ZmdpLNXxjVheg;?RL6u;+?a3nj%3sBD^=X#@wu0aKpvLl5bGd z7ixzCDl&S25Is*fJ7;etL|lQXOSI|`VPa_67cycLFplu*gAUt5+qS9h{7Qq$(9jBg zL$R8~=gNS7qm+qah0aXzYhGAx&X>xgk`nUO0pt^Gm9M(^6UMMxlrC*JHC5NlQ3$n1 zNx}Xt?`u^Nwx{l(FaT2cJR729n`$9C7HLzUVW=Y=L-fl8ujd9;_3@MJ4U(8ZYPApo zZpk~C6074jF!X23vHEF{`W+3Dj$p&mp5*TSoHb43T`g9>_9bKl006Y#0m07Lz`)*) z_SYNz&&ZG#yAZK}2N!Tcd4&yk!_qO!u41EZC4noaj<99onMM$}l|e zwob5JO7RG`Iz2!7Nz(A7O>ywNv`T+unusj=GA>%wTM(6*09MPX`Rl><^ank1;VA_tGxb<`=5zukWpOCfR)FIczq!Z17tF6a`L` z46v0|VBnkybH5&dmaGSQE|)TV2bHdM?vJ6D`n=v%EstT2ppIL1=P*A>>deol?h2B& zOX)+R-0g)mrTii31^(ej^kvhx*C+q-^6Mooammt`4%%M}^bCL!Y*0oxTEqqZyW+ee zYkbMVvM0S5gyVWqQ*p`m?7gkEtud>YCe4k_R~ZkdhkG&0KBP(g=ZuQldq=XVP1M0X z_uE@c+KW5eR@|w>^4UTUCy^u0kVumZ5>p+eZ#=G_%NDrrEuC0WI&udvO4#q1sHekl zq~4br7M{*ZM_Ji4a@!k(ij9NLJzu~VCE0F zY^2(ANJF&x(F~}JWWym)R?_>(PJP>WJcQI*78P2h^7BCz#h2V2+yD<~iV$+s(Exr* zXwy$y=1+csg4n>Q%->U-)q4PPlU#;IrV)}GV}cadwlyA>%JsBmC3WU}alWh%%(F0K z`l;!{)R7#s(6^Hnv>%eesNn;%B2-amjMPa%m}2^d=(2#j+t&#hS`aHK8o$e~LS@YM zrvh`5mDhA!gB8(rPOaH&@Ie4Kf{|eDzV^)Pwoxqv7WJ4P%7iK`9O@>c(>6e9c6t17`hj5bW|G~KtM6yKEmQ?03(8s z1VO)4We-~KQQRea2WAOb?Nr?%3e=+8t+O|1_8_-hg(2>WyjNo;zm@#1g6+n2(v74-h=ac?yzY*A(4t zRoX!&chVW|K8^#G-&1IB|r{+ukmf!VwH6dL4m9u-V<5*E4Zlx_M&vLOH#r~0VP`_P zB7}*C;y1C#JZ>Tmu~6j1RrJjC#V$s|F3ryD=~52cT?`gt&WZ9t)J!O+EyeGj7A`iu z5padnAuQC%_TafZ)Y`lnX4M<6VEFJvjXlIt;lBFN(_+$flGgj87?~b~f!`jm3_HCS zVrD}hsbNZIBvg?2Ah331I#oD=zs;GOjQ3PGK0l5c)%UX}+3bU|2f|fjy(1>6CY^K$I4p*~0vNop<0n(4G|#vXV0yR@*1vrt;!YaKl!7D*wVc5V(pn}x2Em25z^2r25G>T`r@m@o@e z5sUO3_?I9Ab{s1rr^IZVFk~9SatVgO_7yQ{5V^g&G~H+;Th{a{M}j-|{*Je)$kKE{kU zzQNpmS+0D#`GvB?%|vlyUc@_5eqyw^Br>41z08(QmW#DX@d>k^+@Bp807|?|;o~|S z*RmuMW4`GRK50gSg}8E4Lks39Yvd%U_aq@kl4FAQxclB|XpHvxoq1<{{94CNYZP<~ zSdvI~tY*w9n@oE5G({8KUr-8OPkX#JL6^7K=aVLvw9@IV_;^kNJ{r{(th?;Mowgab z4vk`T2x(B~N$9|yMrJ7Oksc!-Qd`RgqdXyP&7PKL__4yBL&T{Pi5xP_S07#CM@yc7 z1Crc5T}K?v3#x~;XY@zyPPNe(7Rp$>2-r%REN>+jFd(Xp?_tC`(8w$32rQJzc+&8d zW4z@eRSxCbo1cNqpbIhwpU-Rg2#k7=x`T6WT(hQ`YLXQas`W<(Dd4JeG=+i73sgrM zYr=@ll(hNNsCCW|kfM>5L^_74UO}~%UqS2fq?59=0KcSImL+TaY#BlWH({)<`g;w*004II{!9AC_-FL3I=wrjcHX>Ze_26sx{JAkO$2ZQ zXpX4l{un!LO1!wlm{_kj;Lb4ME}7@BPN1@r!(<*|%K3A&aZ|B=GtJqJ)z}0Y;f|_0 zy@8tSy07)E&h=TBz0qMWvw$;*-;emlvo=a_n-=(#rdj(O|M+>85ia+6W}9^6viYfkf{;U8`d651?2J;jZ&sOVQ!P+!ayj|R@?xIH z1?eYSoK+ioYvO&r-Y^+p9Z_>ZgsuI--x3xvj7)KXld=ks4B4?Gw{z_?rg)uM%8BgR6#UDI zBpyXWd#rs1%;%wY1CcmydPVpnDfL)%)nKnIl&9+nBAdr!QEE_U@zN%JNSus5R&^m) zJ~%xcTOM>7}h@c}j~md+yQSx~c8))~Ri&vSH>% zaLV)Ilii|L;o%LryRk;C81CZKizgP~{L}SD+IZSXStGzFBJ;m=2Xxcmo(RT8dRM$&ABM3%++ zTQC>TkqNdtI=TGmFZhh?B9ON6L2CFm@aRjIz+JxJ$>@X~?&*)hqr1dKO+Mz-x+Y`5hD)Z4`!N^I=vk(s)Rs#yvV?1zb{)2m!?)H7x7SPz>!hCl zSlPEof(w-RL)2e|0kWZ}Tb#Sm07ut47TLRWXzJ;!K9aR;SiGyX1TPqCF?{1Uu2gc- zhn0sdKC)IdLv@c7=JgkEhr;F;LS>ttS7|G$vmMA)+*R(#5y!THfK&GSGwOohcpAH;AP~ zs9Rk1s`g@v*_BzNnm9gchRpbC)l)%R))Z{0skhpoSnH2qG#X2_;@G&wGVd@o1!PT9 zp}XYdeWsJ8xPnV?3FwfTywpf3wPJvE9?(A>zrIxDF8B;m@k7rtmWjI|rSO;>-CsSf zKr^z*!l`mGIpb4Xg_RcYqPP%qT^oUSI*8=5~KS;)mV;N{lU-8pCl6aBmqrw zie8PLH+*Raj2WGf!7Q;0C@nK#^E{E`iujO+8=IQ9*TnR}^($>M(6RRtUg2k^byMzb z7O^S2((>b}p@f>YSQutY*%a4bCzZ>7)BtL!Gu~DZ8cigrH1PWeu%Pgz@XPYe&JSh4WBqxf=l?m zO;J&k5@FwMaSc7PsZl)&f7Q6xrxzo+P;3(CG4L8USA$^FnTaoS`IP07lnBr7%z_Pa zDR}DZvf(BjX_jAaxsH4u2B70Slq?_cq2ur_roqBn9H=!}3mEyag($jf9rLE#Yor>( z{!!QsxpJ?fPHTFN5jC~9Ge6iDoN`!X$KpDiRfqD!+~NLlOklsYTs+ayJw4lKG ze+^Da>Xxt5E8zxRV?gG>98GWYtQc0^MzH&Ml;~)dW>|8D1fza*BTpZ^wkEbbVH~-Q z^9R?~^wEY38~29`s~g9nta)m$vC7bwqaMZPm(|h4L@nIH1KXyy<@fP-vaHiKEq;e% za6Ah2^LMZ)FEclUpV4nl`fR+!l8dA0xkrcdhd(nG3iNhz*WTRT&^u?HMB@9+=&baO zt1$SX*&F~I^d=>&F0k3__0P(ezg>RCt(9t&1`rSCyXsPqW(QypQylbI$`D*c3_$lFdbCY%+G)7xH%96pV73F z)MLps;tR&^M{g^0(}cDb{qDW$p-8_r)36zaV8cQNE^Bz)TCvAxRbN}~?H?}mgM%-N zc>;;}-C^x8R8E?(SJ#g^*74BztUsb4u=lE}Fgzew*L1nJl_20DMTQ%r5hNDN5Vu^1 z%VP*Ow@vr96B#;vJ6&Zf`W7h|1u7~Nj!DP~t!r(mzWXk;$v{_}6K*1y_0#K#qXVWX z=4nJWDaQCM>ccQg4}ve2kwRUqrkw9#C=_T+1rGAk-jr93C~Y$;-y>Ll2!0v-z5$`U zhhSUCyeZC*A4a!UM*n(!eHU@tXi=JpAcl;yV0tnGS0gMPBF$?oif6RoHzfh~B9U6@ z^d5Rj(s1&n(zwu8=Q>N$%~YLw$9698(uIv2Tl&QWDv>*DK?f277V2O`j#r`rp>U*! zeS9mK0f>!Kx(R2jQ9O+Wb%#$T;O9?Sk9&38#?LNOnPB z)m)_ojk@x{Tuh@>oOnUGKC`LtO24s4MMcGxc)YofHyUkmApBulUpC zGr6SsO38Lou@HsL&VxdhMv^ipCx^g`eu>N9EVYb5R;*6id4JDh|JOQt7}#lh=GVoQ z_t5{Pqi24*xRU#zQl0Ks7hLP-EO=88mvOBY-B%r?-xOn;bGgJ>W9QS3fZ~oOk#dq5 z?J1K9D-OmGq$xF4DzG8KwpkEDwa^?oa^DykCF>+3E6sv4Hw=wDp3W)Xela{I(OUlrfo20IaSwyJ#^ zawa{>uymUqgRp2^N{LF4e9gSlkU1I0;EBI<^8!bLAq&j8274M3!mA|5)K;}lNp**3 zZtHz_#4x86$9|V8tx0l0_6Zs#H1SSbLEBI8f}cThQdpKM@q*y~gW;6iD#Swt5U`^3 zwyaW~-)KR)mnYQhLMofJ`4upc^}8bY==KG>{HtDC_nvHg1dE1tM06+JcTiCbq*@#B zYL7Cc>w0lnsNoB@WetZ^Pa`123g(ncPOUFMx}P|aaQyYmr`?DtBSBRnNQBSm(A{We z5b$rI<4(OWQ^K(CZH4#t)4DgTW4dKz!;lUlmYo}etjeeM%e4^F`M7~(iUn7}PGm05 zkk6zEt`~{dAL5)#Ju*d`=U;^x|Lgk2rDe(!-tx(jW5!l>>h5#Ez3U=RA)|2e=Q6}8EBZCa(8(^N9ClQ zsY5;|X3a4()YbyD6edAXt~x$yl^18(Yc-p^>$rp$QF1d3qQA;OCzLG6kleq_WMs?U zU<6nU(Pi~LX&#v)l($6O78&%peYu)Nh>8)S)18A^)nicA;O5PJf9k0FvOXsE*uPn% zX(F``tfWAOZ89p>%*~#`+O9Ak=qtVg)n=Ms%RvCkZ*+ z)gO%y@En1y$f#cyCO7zjCDR6$uY*oUL3gmO4bz7hM*$FxyxbcxUr#wp5V8lhs_yKE zF}8OnyRWzkIq!rFu^*0b%owEsl8kP;EfD&Qsu_Y7!!p0NexEM?vT^rHr2a9(Gyf>@ zxXL;H@vT+=| ztwMvYbKi27y<4vP>cXCMo2(d_cz==Gx9hl_feYszuj?H%ubdL`^@`W@r@gU(g~1=M zzcN*asuEV1tZ;3pyIy$L8M``S^D!V%v?<_)?((TEO4SPI)xeatde zyOhgnzzL}bM950KoN1JrDByb*2;3A`Q?oZG1-q|#U*G-2c7i@?UHQo?iO!zSFOSOt zG`@5TAew1YFh!(%)$*H@0X3i8ntc$uj2LAS0=mYE^GmCl^QRsneDLc+TkHlOm16T& zg&2G)J(qYRB7Y-78icad!XR-$Z&+{3PVs5mCRuShDd4zukp5-#aAVPrD^Y%hrMr+N z36xvfdc8$MpVdq9G{KW+XUv0|A8y;$8gnLWDL5swfQQupPjSz?cwCBrx~mjUvykIP zNXaZTDA%ss5#>n_sSgj5W!h+0=&+PwWZ+@8B`I6g>>SLbR{)aKdL5dVq#GCtjR4r7 z`OPRLq7BO%luX8qQTVP87>=ZyG%K2Jfu7=tlT(izo0o?Ts)b=@O7Op#I0NRvB*PxJu zy0|8pLg8hmRo7`cU>kPeNl2v7#$;zD zn}XsRqSYAkpIn8WXnk`I(ER4?dbxWyk((KT!^`7(nVY|5zSwJ`uz0(_F!ua-uXov3 zYo*D3*BO~8{8-8Bem*po`QRNT1r@C6d3V{cBctVcwRf_@eb&wjii5P~kpdTN87ugu z4{>}1tv5amy8F)YQcp4+n+CRp95XWvl9{*@P@BwnEuqeEEhRB1%8px#DB$Z?}u~^2)x=t@O-K}UO zS>}M+c9j4hpY8&Dg>;yH1BOeM?JW9m!w(t86RLEUbn{ukPgp~l;?!OU?ZXm&^klu;?CM%uM(0*#3<8HQr7KSM%8eQHfJ#g7D$ENcRr^ZzL zd)8aPLej4fIK&anGPEF0CYwQDz~P?s3Aox?_#0Cr1$i5#9 z)o^q6v8=&e5RY9~>v|v@YpLWkoDwY&M zHUwRQFgZ4YXt2?beUd5_FbONyqE`jdq9s}2z?G+3QAoG0E6~v;pDl27AgP#%!R{n% zB80?R$&j-2q_<2rpJT$j!W5Y>g*+<4)GodwbEu?aeKBQx3vV~PeGmq1x9*VcL0cqX z{@76@vq`wN?IY>{8m!ncVfjr>Bt@@StxB?gbl(Tp0;7_9@RKvhrkih~bq~NdgYnA(|(uxCO?pfjY3}S$E zt&o7uPB>7bhl>`4jM9`Pal!%jOOR)h5nOMq;bT+<&vvbPVwYr%MTs{)(INA{d^Y2> zu(;@_9(9>SrX7MFtZGrH-+`HPNkxoyqkw?{74^25!b_X2+=6SSO=T~TH(1y4}!dClKSF#9p_2Dz)H9?)g1T7Y*)XAKYYl#cH zb61DwXzmZCGUD*kD@NQpbPWppr+1^g6apfWXa~S`V>em#1kRN@3zQ(T9z85LqNt+k zIPb>U=7cdNQ{pUC&X2D<7swjVMmd+*wfZL;_Uy+@4qfcFYwT>#MwWK&!qU}es~xJR zu97ffuAM{nuZ>y0qxB`Rn)RS+x}O4IwSrc{kw}U??62Z$;CII9Xo>QjtM8nL#0c%vW9oOrfpT>X@#>HDnQ~`_h#}Qu(s=Tq~T%&I<;+|?E)vrv=}KF z_mh9y2O)Aw3diJ^1rK;C_sVG%g(NY4h8Iz_7scldSd-Gou*D;Y2^_v4mWvxTR!YBl zTNyUXN_{~PuHyW4l`grXj|*fzr9WD_(L=hdBiIT$oxmwIHGw*-@12c(i z5v3J?L`)Wj`^wa4g;MZ^af+hH#^h~QL1)U92Ytu!b_O<^NUbR7MvdBb6q=%uH}@hl zeT-28hImUMZ6YF0AGVZnx5)R`&c7t+3WehXlGK$(3V0&;yKD-eS8`eKy1^!S6EmRY z>&v-dhyxL*hPJ1%MPd%`D#>mr=}FH`BCEXiJi=pfKxt$ zLC&n-JEytzZl=cjK*kCU)gHRa^%LEEkuW_fmCy>2!`pEEjH1Md!_~a#wUSVKD`O!_+~OD__$Z{RgIz zMs#GfQKO2zU=JLwAYM3^udS!5Hq1nvd}6a(v;7w*7bJvvyHKP~(2vaN9j-3?a*fUb zuDz?EOw<+?{ME}Xgd+|@!Q=Uo+Mxqz!wd4W!5vPSx;%N(r}m*DPGH?76m)o5JV1HH z9rOd2y`WuXWj**WZJ$U6_NR>YFVsVLwB{0H(5}#t9`da1WH{6TWO^fGB-9SVG>l9i z7}V;Wveiim*CzPb>gtW!_>*6j6`)cT9lUIi00t`96ny zziq#K+SA#Nyg3mShIMy2zvsivtA|VGUH-<5$eogk7IoV|9j0@8^FGAzS*zh7Gck36 z;62KkEBtVU7y?!76^W=J>%mBYN`Q^?#m#2b1@;GQHx}PJ_z@*)U*PC{)&;9G%P$7c z`fIxj+hFtZ$3xCIZPGb(WEEXxNh4{H1GMdgrkg`ZkUGeyt zWlURsvh>ExWK4BFqE(N*B;#2i7_e=3e@;RBnu$DRUfFms3IG7oKL)k2j;(>dyuGc7 zrO~gkou(pdway0T$-DR51-^G2?mxL@Kc8DBsT(vsD{Vna9a%JDL5aMJ{B{1}hE*CU zrw6ey-Wi_}$L%ort}S_D26xElRB1=cl(zE*h8G-1n|nZX&mAtM9&ek}H$lxjlW=Fh4sv zXjtCfs?*>y#~HG1c0Y!>f8uo=>X|A5zBy=^zAjDn zJyHoSPVK7V-M8q=&3JLV{dC6p0h0EzSJ}gr;UfmrD7PS4-h6|>S7k> zoa&xyC!`7pE&B9?PLMQWXo1Vw#D<~?#=3e_*vc5s`Js0pgpFmz>)>L*2rSaPqhz-Z zM#XN!J^^cBoD{A=C?LRTpqx{+Q;f1ju@m$Ycq)o1b{~B7g+N|Li&I)M#>q$9HbDg8 zdW6Qi63XkW3y`HU1lnk%p48>p+BH%ko@gQ-+lQ8Cnd+s-EjWG9y*o$Eb0wiNB)5TY z)&(>QV3(-%i|(mUD7ddz-$jyHs|2PA=1`|x*({snu#=^NgttTX9c?LWDmhQ*8Xw+O zPh`T^8F&=!rt*ex`eNkF#daD@HqH~^^j_BTg*OmBUs|=hWpkNq(bk?&1FLkCkmvs32yB`ZD^3x7zg0tn17tq@ zXPI;uGtKZjO(!d7R6rtTou;X^$4oj0>;y^w&T}$4XvZY}-GLx72cLGu0eAoijgC0{ z5cC8H!eE1Bcu+emV=IQ#22mIzaz&%a6Tq{w53L3;2a9}Zm@H!C+gZZ%aZ~7okS5w% zo-_H}i>S+XxR&4W&X!5x2~|b9Uiccf$44(HsJpCg+n{GmJPhesG}smn@fEziI@N{d zt&M$Yh9idCd$4mpdM9CneN!{B4(yK*56glt+8U+z7cZ2=F9Bdg^llV4-yZ6v>4`SY z%v?X2t^FAIeIj;GVsmP3@Lngou;4^R@?oEQ5EDcu(>o~AW&7JX=PnS!yC3ct&|biK zhevU@aq*d|)T%yx^dsz^y+BAmr=UE{9fra++}Q zbJB-5OeXD-vU5@pBng#*IMY@4Y>5^BNR_b?L8N>2@fn~_1xKtz3~1ZIvP=2U&NJl! zWmFd%B5=i9T%;(iXu>$#aEFB-LET$McutSUCMobtgWfy^|3E58>0o$E2=#2VkK$#jDv@Bxf<_oIAS0Q@&}Ty4&}{_1>?ZI%+CZ^H}*Uv ze%i$30J(6J`xb0-10@`_UWRMQB+I*VJMa2zfMq&vn`q=ak(_CPiE>GNeinr5jwzCW zRt&L}n$Eg$E*bp=Fx>u%QWuPYT-dpr2z$LlWouL(8%Be#mIpai6DiTQY1-Pu`8Eed z0j@EoG4jNi)BT4SlB}d~0Qfl-%`uisw=hSYI-syxvdovj40&cY!X^Tpgb!)mO=a0mi5>cOX>qxF{a`BXsYk8 zxus1#RO6~sw|VMs{MBsxi%1aETv0kxG;Jxs($eC=eNigNP}TmjL{Dg4p51fR5fH^u zJlk_(!7g+IccGZ$WhJH-=UVT+&`Q^xP;GiB`*Lv0sXiY@c;Iqb=6)L$JsuUO!hrtO~=Fzup)6FTvK z^qqAh;tc#4LaZf@KSS~aAgsBNb1iP%Kz#SGJL@M9(WSRc_sL5Y^(xd~j{vINk`LdX zNhpQNJ)Nh%GE0RE##77>rJ{elc|_tSI5bgho!wArTEJWfWx%S}I?3j$OkSi!U((=8 zPA^&VdTl|**iovMb*mD1FeiUWV`1#90e zSdS>BrA>qTl2jFc^#a^*9p3drmBKKEfvCa5yj}!J$LC|96u~L3)bj0 zn=H#njl>tHLY*L-u>r5wUeNc;1TKQnu2H4)@jrV3v-%F{6Fh|EOiIti@t@1V>J^%KPbm3_U!a=lva%&-Zk=B)ekvJ|4rMpWxWjQ$ zLp9VgJm8bIW6Xa%#O*?+b#^21{G_2|AmvC{CvmHopgv+nL80pMooQb$fD?wb;%gMI5qKrpnE9a!>eDbRKuUw5C&?N1Jwt>7;cK z$I>(Mg8j~C{x&7I**4sjVhDOc8WPPkx<9O`J-gR5t5-#TRaY?rs$MjC;yRdBb;JZQ zCHeytq=>B!D%b$M&}l!Ih>mal5_F7 zHJgY54uBNYn2*u2Ml*z*$48Awoh7uGTJSb-v zghzlC2qY z?2yIk!V91a+hFsKbr#l|mgmSRyb8;hwsY0|aK-HLX{9}>Ef~rf3e^T8(FSxQX}q*( zKTj*OlUZ_u!_XR-)dtGv^9ZqN1F{d4YXiH4wIi36nk0Ydyy^USM9hx~e10Q0^U9;z zr-?6-3?Cx={x`|2XzzvfBOU{;rVsVw#0 zpJ*>DqgcOlI-^_I>?xp(sV6eR?uDH8#ZN?t-SH^_9IMk5b1*xTS}BVjD+X%#mqsBrYK%{Wu+C+i~odLVNhjQknHf}0-99K z7q3p+mni(!UR|6FPBZhhDPIEL;k() zNCDDecTQ$==M36>zJ1qaPnmj zc1UTB3g2VBOo+hk>;ymdZYNm#>lMPYB5W zcc;Vfx6}FC>HO_<{&qV5lTL^6Z>RIO)A`%!{Oxr9C!Nk~TK(_o)!);rzo%D!Pp|&x zrdP~=JDtCo&fiSuZ>IDApXnfQKfJ2V002G#0RX_iRufQ?T?} zMepx|La)nVelZi$zH~?dCsOY3Cf&&Vi`9XtCJdBmRM*3Lo98nu!at_e4_;rR%)&7u z(hj}cY;cl}YzLM=x3#ONmSRPdi2#ymLKQo*yDn38kwcd0iC5JqMdcEzFws_2GE|UP z!jwsscd$XQoDvz3&#=#P7LxZSoMh{=oWpE&Sy)hPKTaH089w?R0g&3bhf-Qg()C$G zL0|C+k>;%e%Xy{L0E0(l`$5LlCJBMO*kdORKD%T~h>VDT&Anz!x9>CWc(69cEyD_t zni7(lH*xmz(Nd0-St`m_II3XFB0x;D1sHM!|{ zUAb%<<}Q^#@x}w96?D6@JCEU^Vv$fFvSEPGL+EwFM3}-9Aa$}jI`LYv+Pa6G7F*X^ zr;;?pWXLDVHsK)10QBq)eJAVwrzt&p@RFq5*AD3Y`YqhQc0e6#>%aToYsdS?krvw_ zz4&v#Wc>a6=#w&F>LN9E5o42{>>|n|AfpXQ7L;IYmjL6gDW@2|{?3fX@EzQj=U%tXR9J_bVN; zPs|B~18~8&FLgHXb*3hBKKXEn_O$L6Mg%TQ;M~$AYKZA)-6|e)jcDs7{2}-F-K122 z;PIP2^z42Y^Dc*;`xn`teY-lBwLx^&;9fNcK#$60Qh9{kJ9g{dI-A%wIC^wo$rvYzncO8WJCUH{9lxwdyDh7$k=bBv)3(S|G0_&C^_~P0~WLYH-Nu|CvO4Y3O9ZOmT~+yfWKuNZvo%R zAbtZ@a{f1fzeN#m0pI5LegoEU{Q`U=Dfm-~!Cwa@<^L<7zfy>Q9W+h&uYmqa5&U&f zc=5ji`fCaBuY(3i{}s?*Q~bA}|4!O}KPCWx2RQ(M|Df=1oBuoI`q$>}ivQC59|Y{9 W1n6tb__@ay4dBP?Uy3R}Km9+orSC8R literal 0 HcmV?d00001 diff --git a/BharatFinTrack/nse_product.py b/BharatFinTrack/nse_product.py new file mode 100644 index 0000000..d25639f --- /dev/null +++ b/BharatFinTrack/nse_product.py @@ -0,0 +1,221 @@ +import os +import datetime +import pandas +from .core import Core + + +class NSEProduct: + + ''' + Represents characteristics of NSE (National Stock Exchange) + related financial products. + ''' + + @property + def _dataframe_equity_index( + self + ) -> pandas.DataFrame: + + ''' + Returns a multi-index DataFrame containing + the characteristics of equity indices. + ''' + + file_path = os.path.join( + os.path.dirname(__file__), 'data', 'equity_indices.xlsx' + ) + + dataframes = pandas.read_excel( + io=file_path, + sheet_name=None + ) + + df = pandas.concat( + dataframes, + names=['Category', 'ID'] + ) + + return df + + def save_dataframe_equity_index_parameters( + self, + excel_file: str + ) -> pandas.DataFrame: + + ''' + Saves a multi-index DataFrame containing the characteristics + of equity indices to an Excel file. + + Parameters + ---------- + excel_file : str + Excel file to save the multi-index DataFrame. + + Returns + ------- + DataFrame + The multi-index DataFrame containing the characteristics of equity indices. + ''' + + # Excel file extension + excel_ext = Core()._excel_file_extension( + file_path=excel_file + ) + + # saving the multi-index dataframe + if excel_ext == '.xlsx': + df = self._dataframe_equity_index + df = df[df.columns[:3]] + df['Base Date'] = df['Base Date'].apply(lambda x: x.date()) + with pandas.ExcelWriter(excel_file, engine='xlsxwriter') as excel_writer: + df.to_excel(excel_writer, index=True) + workbook = excel_writer.book + worksheet = excel_writer.sheets['Sheet1'] + worksheet.set_column(0, 1, 12, workbook.add_format({'align': 'center'})) + worksheet.set_column(2, 2, 60, workbook.add_format({'align': 'left'})) + worksheet.set_column(3, 4, 12, workbook.add_format({'align': 'right'})) + else: + raise Exception( + f'Input file extension "{excel_ext}" does not match the required ".xlsx".' + ) + + return df + + @property + def equity_index_category( + self + ) -> list[str]: + + ''' + Returns a list of categories for NSE equity indices. + ''' + + df = self._dataframe_equity_index.reset_index() + output = list(df['Category'].unique()) + + return output + + def get_equity_indices_by_category( + self, + category: str + ) -> list[str]: + + ''' + Returns a list of NSE equity indices for a specified index category. + + Parameters + ---------- + category : str + The category of NSE indices. + + Returns + ------- + list + A list containing the equity indices for the specified category. + ''' + + if category in self.equity_index_category: + df = self._dataframe_equity_index.reset_index() + df = df[df['Category'] == category] + output = list(df['Index Name'].sort_values()) + else: + raise Exception(f'Input category "{category}" does not exist.') + + return output + + @property + def all_equity_indices( + self + ) -> list[str]: + + ''' + Returns a list of equity indices for all categories. + ''' + + df = self._dataframe_equity_index + output = list(df['Index Name'].sort_values()) + + return output + + def is_index_exist( + self, + index: str + ) -> bool: + + ''' + Returns whether the index exists in the list of equity indices. + + Parameters + ---------- + index : str + Name of the index. + + Returns + ------- + bool + True if the index exists, False otherwise. + ''' + + output = index in self.all_equity_indices + + return output + + def get_equity_index_base_date( + self, + index: str + ) -> str: + + ''' + Returns the base date for a specified NSE equity index. + + Parameters + ---------- + index : str + Name of the index. + + Returns + ------- + str + The base date of the index in 'DD-MMM-YYYY' format. + ''' + + df = self._dataframe_equity_index + df = df[['Index Name', 'Base Date']] + df = df[df['Index Name'] == index] + + if df.shape[0] > 0 and isinstance(df.iloc[-1, -1], datetime.datetime): + output = df.iloc[-1, -1].strftime('%d-%b-%Y') + else: + raise Exception(f'"{index}" index does not exist.') + + return output + + def get_equity_index_base_value( + self, + index: str + ) -> float: + + ''' + Returns the base value for a specified NSE equity index. + + Parameters + ---------- + index : str + Name of the index. + + Returns + ------- + float + The base value of the index. + ''' + + df = self._dataframe_equity_index + df = df[['Index Name', 'Base Value']] + df = df[df['Index Name'] == index] + + if df.shape[0] > 0: + output = float(df.iloc[-1, -1]) + else: + raise Exception(f'"{index}" index does not exist.') + + return output diff --git a/BharatFinTrack/nse_track.py b/BharatFinTrack/nse_track.py deleted file mode 100644 index 1094d01..0000000 --- a/BharatFinTrack/nse_track.py +++ /dev/null @@ -1,200 +0,0 @@ -class NSETrack: - - ''' - Represents characteristics of NSE finance products. - ''' - - @property - def indices_category( - self - ) -> list[str]: - - ''' - Returns a list categories for NSE indices. - ''' - - output = [ - 'broad', - 'sectoral', - 'thematic', - 'strategy' - ] - - return output - - def get_indices_by_category( - self, - category: str - ) -> list[str]: - - ''' - Returns NSE indices for a specified category. - - Parameters - ---------- - category : str - The classification type of NSE indices. - - Returns - ------- - list - A list containing the names of indices for the specified category. - ''' - - indices = {} - - # broad index - indices['broad'] = [ - 'NIFTY 500', - 'NIFTY 50', - 'NIFTY 100' - ] - - # sectoral index - indices['sectoral'] = [ - 'NIFTY IT', - 'NIFTY BANK' - ] - - # thematic index - indices['thematic'] = [ - 'NIFTY EV & NEW AGE AUTOMOTIVE', - 'NIFTY INDIA DEFENCE' - ] - - # strategy index - indices['strategy'] = [ - 'NIFTY ALPHA 50', - 'NIFTY MIDCAP150 MOMENTUM 50' - ] - - if category in self.indices_category: - pass - else: - raise Exception(f'Invadid category: {category}') - - return indices[category] - - @property - def downloadable_indices( - self - ) -> list[str]: - - ''' - Returns a list of all indices names. - ''' - - output = [ - i for c in self.indices_category for i in self.get_indices_by_category(c) - ] - - return output - - def is_downloadable_index( - self, - index: str - ) -> bool: - - ''' - Checks whether a specified NSE index name is downloadable. - - Parameters - ---------- - index : str - The name of the NSE index. - - Returns - ------- - bool - True if the index name is valid, False. - ''' - - return index in self.downloadable_indices - - @property - def indices_base_date( - self - ) -> dict[str, str]: - - ''' - Returns a dictionary where keys are indices - and values are their corresponding base dates. - ''' - - default_date = '01-Apr-2005' - - start_date = {} - - start_date['01-Jan-1995'] = ['NIFTY 500'] - start_date['03-Nov-1995'] = ['NIFTY 50'] - start_date['01-Jan-1996'] = ['NIFTY IT'] - start_date['01-Jan-2000'] = ['NIFTY BANK'] - start_date['01-Jan-2003'] = ['NIFTY 100'] - start_date['31-Dec-2003'] = ['NIFTY ALPHA'] - start_date['02-Apr-2018'] = [ - 'NIFTY EV & NEW AGE AUTOMOTIVE' - 'NIFTY INDIA DEFENCE' - ] - - date_dict = {v: key for key, value in start_date.items() for v in value} - - output = { - index: date_dict.get(index, default_date) - for index in self.downloadable_indices - } - - return output - - def get_index_base_date( - self, - index: str - ) -> str: - - ''' - Returns the base date for a specified NSE index. - - Parameters - ---------- - index : str - The name of the NSE index. - - Returns - ------- - str - The base date of the index in 'DD-MMM-YYYY' format. - ''' - - if self.is_downloadable_index(index): - pass - else: - raise Exception(f'Invalid index: {index}') - - return self.indices_base_date[index] - - def get_index_base_value( - self, - index: str - ) -> float: - - ''' - Returns the base value for a specified NSE index. - - Parameters - ---------- - index : str - The name of the NSE index. - - Returns - ------- - float - The base value of the index. - ''' - - if self.is_downloadable_index(index): - pass - else: - raise Exception(f'Invalid index: {index}') - - base_value = {'NIFTY IT': 100.0} - - return base_value.get(index, 1000.0) diff --git a/BharatFinTrack/nse_tri.py b/BharatFinTrack/nse_tri.py new file mode 100644 index 0000000..a1a046c --- /dev/null +++ b/BharatFinTrack/nse_tri.py @@ -0,0 +1,166 @@ +import typing +import datetime +import pandas +from .nse_product import NSEProduct +from .core import Core + + +class NSETRI: + + ''' + Download and analyze NSE TRI (Total Return Index) data. + ''' + + @property + def _index_api( + self + ) -> dict[str, str]: + + ''' + Returns a dictionary containing equity indices as keys + and corresponding API names as values. + ''' + + df = NSEProduct()._dataframe_equity_index + output = dict( + zip(df['Index Name'], df['API TRI']) + ) + + return output + + @property + def non_open_source_indices( + self + ) -> list[str]: + + ''' + Returns a list of equity indices that are not open-source. + ''' + + df = NSEProduct()._dataframe_equity_index + df = df[df['API TRI'] == 'NON OPEN SOURCE'] + output = list(df['Index Name'].sort_values()) + + return output + + def is_index_open_source( + self, + index: str, + ) -> bool: + + ''' + Check whether the index data is open-source. + + Parameters + ---------- + index : str + Name of the index. + + Returns + ------- + bool + True if the index data is open-source, False otherwise. + ''' + + if NSEProduct().is_index_exist(index) is True: + pass + else: + raise Exception(f'"{index}" index does not exist.') + + output = index not in self.non_open_source_indices + + return output + + def download_historical_daily_data( + self, + index: str, + start_date: typing.Optional[str] = None, + end_date: typing.Optional[str] = None, + http_headers: typing.Optional[dict[str, str]] = None, + excel_file: typing.Optional[str] = None + ) -> pandas.DataFrame: + + ''' + Downloads historical daily closing values for the specified index + between the given start and end dates, both inclusive, and returns them in a DataFrame. + + Parameters + ---------- + index : str + Name of the index. + + start_date : str, optional + Start date in the format 'DD-MMM-YYYY'. + Defaults to the index's base date if None is provided. + + end_date : str, optional + End date in the format 'DD-MMM-YYYY'. + Defaults to the current date if None is provided. + + http_headers : dict, optional + HTTP headers for the web request. If not provided, defaults to + :attr:`BharatFinTrack.core.Core.default_http_headers`. + + excel_file : str, optional + Path to an Excel file to save the DataFrame. + + Returns + ------- + DataFrame + A DataFrame with two columns: 'Date' and 'Close', representing the daily + closing values for the index between the specified dates. + ''' + + # check index name + if self.is_index_open_source(index) is True: + index_api = self._index_api.get(index, index) + else: + raise Exception(f'"{index}" index data is not available as open-source.') + + # check start date + if start_date is not None: + pass + else: + start_date = NSEProduct().get_equity_index_base_date(index) + date_s = Core().string_to_date(start_date) + + # check end date + if end_date is not None: + pass + else: + end_date = datetime.date.today().strftime('%d-%b-%Y') + date_e = Core().string_to_date(end_date) + + # check end date is greater than start date + difference_days = (date_e - date_s).days + if difference_days >= 0: + pass + else: + raise Exception(f'Start date {start_date} cannot be later than end date {end_date}.') + + # check the Excel file extension first + excel_ext = Core()._excel_file_extension(excel_file) if excel_file is not None else None + if excel_ext is None or excel_ext == '.xlsx': + pass + else: + raise Exception(f'Input file extension "{excel_ext}" does not match the required ".xlsx".') + + # downloaded DataFrame + df = Core()._download_nse_tri( + index_api=index_api, + start_date=start_date, + end_date=end_date, + index=index, + http_headers=http_headers + ) + + # saving the DataFrame + if excel_ext is None: + pass + else: + with pandas.ExcelWriter(excel_file, engine='xlsxwriter') as excel_writer: + df.to_excel(excel_writer, index=False) + worksheet = excel_writer.sheets['Sheet1'] + worksheet.set_column(0, 1, 12) + + return df diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..461691f --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,3 @@ +include BharatFinTrack/data/* + + diff --git a/README.md b/README.md index 86711eb..2f722f8 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,21 @@ # BharatFinTrack -## What is BharatFinTrack? -BharatFinTrack is a Python package whose concept originated on September 1, 2024. It is designed to simplify the process of downloading and analyzing financial data from India, that is Bharat. The features of the package include: +BharatFinTrack is a Python package whose concept originated on September 1, 2024. +It is designed to simplify the process of downloading and analyzing financial data from India, that is Bharat. The features of the package include: -* [Nifty Indices](https://www.niftyindices.com/) website +* [Nifty Indices](https://www.niftyindices.com/) + + - Provides access to the characteristics of NSE equity indices. + - Facilitates downloading TRI (Total Return Index) data for all NSE equity indices. + + +## Roadmap + +* Add support for downloading equity index price data without dividend reinvestment. +* Provide a summary of daily updated values of equity index price data. +* Include NAV (Net Asset Value) data for mutual funds. +* Include NAV data for the National Pension System (NPS). - - Provides access to the characteristics of NSE indices. ## Easy Installation @@ -20,25 +30,32 @@ A brief example of how to start: ```python >>> import BharatFinTrack ->>> nse_track = BharatFinTrack.NSETrack() ->>> nse_track.indices_category -['broad', 'sectoral', 'thematic', 'strategy'] +>>> nse_product = BharatFinTrack.NSEProduct() +>>> nse_product.equity_index_category +['broad', 'sector', 'thematic', 'strategy', 'variant'] -# get the list of downloadable indices ->>> nse_track.downloadable_indices -['NIFTY 500', +# get the list of all NSE equity indices +>>> nse_product.all_equity_indices +['NIFTY 100', + 'NIFTY 200', 'NIFTY 50', - 'NIFTY IT', - 'NIFTY BANK', + 'NIFTY 50 ARBITRAGE', ...] -# get the dictionary of indices base date ->>> nse_track.indices_base_date -{'NIFTY 500': '01-Jan-1995', - 'NIFTY 50': '03-Nov-1995', - 'NIFTY IT': '01-Jan-1996', - 'NIFTY BANK': '01-Jan-2000', - ...} +# download TRI data for a specified NSE equity index +>>> nse_tri = BharatFinTrack.NSETRI() +>>> nse_tri.download_historical_daily_data( + index='NIFTY 50', + start_date='23-SEP-2024', + end_date='27-SEP-2024' + ) + Date Close +------------------------ +0 2024-09-23 38505.51 +1 2024-09-24 38507.55 +2 2024-09-25 38602.21 +3 2024-09-26 38916.76 +4 2024-09-27 38861.64 ``` ## Documentation @@ -49,8 +66,9 @@ For detailed information, see the [documentation](http://bharatfintrack.readthed | Status | Description | | --- | --- | -| **PyPI**| ![PyPI - Version](https://img.shields.io/pypi/v/BharatFinTrack) ![PyPI - Status](https://img.shields.io/pypi/status/BharatFinTrack) ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/BharatFinTrack) ![PyPI - Wheel](https://img.shields.io/pypi/wheel/BharatFinTrack) ![PyPI - Downloads](https://img.shields.io/pypi/dm/BharatFinTrack)| +| **PyPI**| ![PyPI - Version](https://img.shields.io/pypi/v/BharatFinTrack) ![PyPI - Status](https://img.shields.io/pypi/status/BharatFinTrack) ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/BharatFinTrack) ![PyPI - Wheel](https://img.shields.io/pypi/wheel/BharatFinTrack) | | **GitHub** | ![GitHub last commit](https://img.shields.io/github/last-commit/debpal/BharatFinTrack) [![flake8](https://github.com/debpal/BharatFinTrack/actions/workflows/linting.yml/badge.svg)](https://github.com/debpal/BharatFinTrack/actions/workflows/linting.yml) [![mypy](https://github.com/debpal/BharatFinTrack/actions/workflows/typing.yml/badge.svg)](https://github.com/debpal/BharatFinTrack/actions/workflows/typing.yml) [![pytest](https://github.com/debpal/BharatFinTrack/actions/workflows/testing.yml/badge.svg)](https://github.com/debpal/BharatFinTrack/actions/workflows/testing.yml) ![GitHub repo size](https://img.shields.io/github/repo-size/debpal/BharatFinTrack) | | **Codecov** | [![codecov](https://codecov.io/github/debpal/BharatFinTrack/graph/badge.svg?token=6DIYX8MUTM)](https://codecov.io/github/debpal/BharatFinTrack) | -| **Read**_the_**Docs** | [![Documentation Status](https://readthedocs.org/projects/bharatfintrack/badge/?version=latest)](https://bharatfintrack.readthedocs.io/en/latest/?badge=latest) | +| **Read** _the_ **Docs** | [![Documentation Status](https://readthedocs.org/projects/bharatfintrack/badge/?version=latest)](https://bharatfintrack.readthedocs.io/en/latest/?badge=latest) | +| **PePy** | ![Pepy Total Downloads](https://img.shields.io/pepy/dt/BharatFinTrack) | | **License** | ![PyPI - License](https://img.shields.io/pypi/l/BharatFinTrack) | diff --git a/docs/BharatFinTrack.rst b/docs/BharatFinTrack.rst index a44b22f..32d8a46 100644 --- a/docs/BharatFinTrack.rst +++ b/docs/BharatFinTrack.rst @@ -1,5 +1,5 @@ BharatFinTrack Module ---------------------- +----------------------- .. automodule:: BharatFinTrack :members: diff --git a/docs/changelog.rst b/docs/changelog.rst index c93420c..50d0a14 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,10 +1,27 @@ -============= +=============== Release Notes -============= +=============== + +Version 0.1.0 +--------------- + +* **Release date:** 30-Sep-2024. + +* **Feature Additions:** Introduced :class:`BharatFinTrack.NSETRI` class, which facilitates downloading Total Return Index (TRI) data for all NSE equity indices. + + +* **Changes:** + + * Renamed class :class:`BharatFinTrack.NSETrack` to :class:`BharatFinTrack.NSEProduct` for improved clarity. + * Updated and renamed methods in the new class :class:`BharatFinTrack.NSEProduct`. + +* **Documentation:** Added a tutorial on how to use the newly introduced features. + +* **Development status:** Upgraded to Pre-Alpha from Planning. Version 0.0.3 -------------- +--------------- * **Release date:** 11-Sep-2024. @@ -21,7 +38,7 @@ Version 0.0.3 Version 0.0.2 -------------- +--------------- * **Release date:** 09-Sep-2024. @@ -31,11 +48,11 @@ Version 0.0.2 Version 0.0.1 -------------- +--------------- * **Release date:** 08-Sep-2024. -* **Features:** Functionality for accessing the characteristics of NSE Indices via the :class:`BharatFinTrack.NSETrack` class. +* **Features:** Functionality for accessing the characteristics of NSE equity Indices. * **Development status:** Planning. diff --git a/docs/conf.py b/docs/conf.py index 0ee65bc..353d108 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -29,7 +29,8 @@ exclude_patterns = [ '_build', 'Thumbs.db', - '.DS_Store' + '.DS_Store', + '.ipynb_checkpoints' ] # -- Options for HTML output ------------------------------------------------- diff --git a/docs/data_download.rst b/docs/data_download.rst new file mode 100644 index 0000000..16f262d --- /dev/null +++ b/docs/data_download.rst @@ -0,0 +1,45 @@ +================== +Downloading Data +================== + +A brief overview of the features for downloading data. + + +Total Return Index Data +------------------------- +Download historical daily data for the NIFTY 50 index: + +.. code-block:: python + + import BharatFinTrack + nse_tri = BharatFinTrack.NSETRI() + nse_tri.download_historical_daily_data( + index='NIFTY 50', + start_date='23-SEP-2024', + end_date='27-SEP-2024' + ) + + +Expected output: + +.. code-block:: text + + Date Close + ----------------------------- + 0 2024-09-23 38505.51 + 1 2024-09-24 38507.55 + 2 2024-09-25 38602.21 + 3 2024-09-26 38916.76 + 4 2024-09-27 38861.64 + + + + + + + + + + + + diff --git a/docs/index.rst b/docs/index.rst index b8c177f..df13ae4 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -4,24 +4,23 @@ contain the root `toctree` directive. Welcome to BharatFinTrack's documentation! -========================================== - -BharatFinTrack is a Python package designed to simplify the process of -downloading and analyzing financial data, including indices, stocks, and mutual funds, -from India, that is Bharat. +============================================ .. toctree:: :maxdepth: 1 :caption: Contents: - Installation - API Reference - Release Notes + introduction + installation + quickstart + data_download + modules + changelog Indices and tables -================== +==================== * :ref:`genindex` * :ref:`modindex` diff --git a/docs/installation.rst b/docs/installation.rst index 51680ed..a93e7d1 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -1,22 +1,51 @@ -============ +============== Installation -============ +============== -Installation of the BharatFinTrack package is simple. +The installation of the package is straightforward. To prevent conflicts with other Python packages, it is recommended to create a separate Python environment. +Below are the steps for installing the package using different methods. -Install from pip ------------------- +Create a Python environment +----------------------------- + +Suppose your environment name is my_env, and you can create it by using the following steps through Anaconda distribution. .. code-block:: console + + conda create --name my_env + conda activate my_env + conda install pip + +Install from PyPI +------------------- + +.. code-block:: console + pip install BharatFinTrack Install from GitHub repository ------------------------------- +-------------------------------- .. code-block:: console pip install git+https://github.com/debpal/BharatFinTrack.git + + +Install from source code in editable mode +-------------------------------------------- + +For developers who want to modify the source code or contribute to the package, it is recommended to install in editable mode. +Navigate to your directory with the `my_env` Python environemnt activated, and run the following commands. +This allows you to make changes to the source code, with immediate reflection in the `my_env` environment without requiring reinstallation. + +.. code-block:: console + + pip install build + git clone git+https://github.com/debpal/BharatFinTrack.git + cd BharatFinTrack + python -m build + pip install -e . diff --git a/docs/introduction.rst b/docs/introduction.rst new file mode 100644 index 0000000..7f50b72 --- /dev/null +++ b/docs/introduction.rst @@ -0,0 +1,13 @@ +============= +Introdution +============= + +BharatFinTrack is a Python package whose concept originated on September 1, 2024. +It is designed to simplify the process of downloading and analyzing financial data from India, that is Bharat. The features of the package include: + + +* `Nifty Indices `_ + + - Provides access to the characteristics of NSE equity indices. + - Facilitates downloading TRI (Total Return Index) data for all NSE equity indices. + \ No newline at end of file diff --git a/docs/modules.rst b/docs/modules.rst index befe653..cd49e81 100644 --- a/docs/modules.rst +++ b/docs/modules.rst @@ -1,8 +1,9 @@ +=============== API Reference -============= +=============== .. toctree:: :maxdepth: 1 - Submodules - BharatFinTrack Module + BharatFinTrack + submodules diff --git a/docs/quickstart.rst b/docs/quickstart.rst new file mode 100644 index 0000000..9f7051b --- /dev/null +++ b/docs/quickstart.rst @@ -0,0 +1,93 @@ +============ +Quickstart +============ + +This guide provides a quick overview to get started with :mod:`BharatFinTrack`. + + +Verify Installation +--------------------- +Ensure successful installation by running the following commands: + +.. code-block:: python + + import BharatFinTrack + nse_product = BharatFinTrack.NSEProduct() + + +NSE Equity Index Characteristics +---------------------------------- + + +Category +^^^^^^^^^^ + +Retrieve the equity index categories: + +.. code-block:: python + + nse_product.equity_index_category + +Expected output: + +.. code-block:: text + + ['broad', 'sector', 'thematic', 'strategy', 'variant'] + + +Index List +^^^^^^^^^^^^^^^^ + +Get the list of all NSE equity indices: + +.. code-block:: python + + nse_product.all_equity_indices + +Expected output: + +.. code-block:: text + + ['NIFTY 100', + 'NIFTY 200', + 'NIFTY 50', + 'NIFTY 50 ARBITRAGE', + ...] + + +Categorical Index +^^^^^^^^^^^^^^^^^^^ + +Fetch equity indices belonging to a specific category: + +.. code-block:: python + + nse_product.get_equity_indices_by_category('strategy') + +Expected output: + +.. code-block:: text + + ['NIFTY ALPHA 50', + 'NIFTY ALPHA LOW-VOLATILITY 30', + 'NIFTY ALPHA QUALITY LOW-VOLATILITY 30', + 'NIFTY ALPHA QUALITY VALUE LOW-VOLATILITY 30', + ...] + + +Index Base Parameters +^^^^^^^^^^^^^^^^^^^^^^^ + +Retrieve the base date and base value of an equity index: + +.. code-block:: python + + nse_product.get_equity_index_base_date('NIFTY 50') + nse_product.get_equity_index_base_value('NIFTY 50') + +Expected output: + +.. code-block:: text + + '03-Nov-1995' + 1000.0 \ No newline at end of file diff --git a/docs/requirements-docs.txt b/docs/requirements-docs.txt new file mode 100644 index 0000000..f9d885e --- /dev/null +++ b/docs/requirements-docs.txt @@ -0,0 +1,7 @@ +sphinx_rtd_theme +pandas>=2.2.2 +requests>=2.32.3 +openpyxl>=3.1.5 +xlsxwriter>=3.2.0 + + diff --git a/docs/requirements.txt b/docs/requirements.txt deleted file mode 100644 index 9576657..0000000 --- a/docs/requirements.txt +++ /dev/null @@ -1,3 +0,0 @@ -sphinx_rtd_theme - - diff --git a/docs/submodules.rst b/docs/submodules.rst index d04f7de..871cf6f 100644 --- a/docs/submodules.rst +++ b/docs/submodules.rst @@ -1,7 +1,7 @@ -BharatFinTrack.nse\_track module --------------------------------- +Submodules +------------ -.. automodule:: BharatFinTrack.nse_track +.. automodule:: BharatFinTrack.core :members: :undoc-members: :show-inheritance: diff --git a/pyproject.toml b/pyproject.toml index bdb2a1f..761248c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,10 +9,16 @@ description = "Downloading and analyzing financial data, including indices, stoc authors = [ { name="Debasish Pal", email="bestdebasish@gmail.com" }, ] +dependencies = [ + "pandas>=2.2.2", + "requests>=2.32.3", + "openpyxl>=3.1.5", + "xlsxwriter>=3.2.0" +] readme = "README.md" requires-python = ">=3.10" classifiers = [ - "Development Status :: 1 - Planning", + "Development Status :: 2 - Pre-Alpha", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", @@ -24,8 +30,8 @@ classifiers = [ ] dynamic = ["version"] keywords = [ - "Nse index", - "Total return index(TRI)", + "NSE Index", + "NSE TRI", "Data download", "Data analysis" ] @@ -39,9 +45,14 @@ keywords = [ [tool.setuptools.dynamic] version = {attr = "BharatFinTrack.__version__"} +[tool.setuptools.package-data] +BharatFinTrack = [ + "data/*" +] + [tool.pytest.ini_options] -addopts = "-rA -Werror --cov=BharatFinTrack" +addopts = "-rA -Werror --cov=BharatFinTrack --cov-report=html:cov_BharatFinTrack --cov-report=term -s" testpaths = [ "tests" ] @@ -49,8 +60,7 @@ testpaths = [ [tool.mypy] files = [ - "BharatFinTrack", - "docs" + "BharatFinTrack" ] ignore_missing_imports = true strict = true \ No newline at end of file diff --git a/requirements-gh-action.txt b/requirements-gh-action.txt new file mode 100644 index 0000000..eab35f6 --- /dev/null +++ b/requirements-gh-action.txt @@ -0,0 +1,6 @@ +pytest +pytest-cov +pandas>=2.2.2 +requests>=2.32.3 +openpyxl>=3.1.5 +xlsxwriter>=3.2.0 diff --git a/requirements-mypy.txt b/requirements-mypy.txt new file mode 100644 index 0000000..e5738a6 --- /dev/null +++ b/requirements-mypy.txt @@ -0,0 +1,2 @@ +types-requests +mypy diff --git a/tests/test_bharatfintrack.py b/tests/test_bharatfintrack.py new file mode 100644 index 0000000..e0992a6 --- /dev/null +++ b/tests/test_bharatfintrack.py @@ -0,0 +1,243 @@ +import pytest +import BharatFinTrack +import os +import tempfile +import datetime +import pandas + + +@pytest.fixture(scope='class') +def nse_product(): + + yield BharatFinTrack.NSEProduct() + + +@pytest.fixture(scope='class') +def nse_tri(): + + yield BharatFinTrack.NSETRI() + + +@pytest.fixture(scope='class') +def core(): + + yield BharatFinTrack.core.Core() + + +@pytest.fixture +def message(): + + output = { + 'error_category': 'Input category "region" does not exist.', + 'error_date1': "time data '16-Sep-202' does not match format '%d-%b-%Y'", + 'error_date2': "time data '20-Se-2024' does not match format '%d-%b-%Y'", + 'error_date3': 'Start date 27-Sep-2024 cannot be later than end date 26-Sep-2024.', + 'error_excel': 'Input file extension ".xl" does not match the required ".xlsx".', + 'error_index1': '"INVALID" index does not exist.', + 'error_index2': '"NIFTY50 USD" index data is not available as open-source.' + + } + + return output + + +def test_save_dataframes_equity_indices( + nse_product, + message +): + + # error test + with pytest.raises(Exception) as exc_info: + nse_product.save_dataframe_equity_index_parameters( + excel_file=r"C:\Users\Username\Folder\out.xl" + ) + assert exc_info.value.args[0] == message['error_excel'] + + # pass test + with tempfile.TemporaryDirectory() as tmp_dir: + excel_file = os.path.join(tmp_dir, 'equity_index.xlsx') + df = nse_product.save_dataframe_equity_index_parameters( + excel_file=excel_file + ) + assert len(df.index.names) == 2 + + +def test_get_equity_indices_by_category( + nse_product, + message +): + + # pass test + assert 'NIFTY 500' in nse_product.get_equity_indices_by_category('broad') + assert 'NIFTY IT' in nse_product.get_equity_indices_by_category('sector') + assert 'NIFTY HOUSING' in nse_product.get_equity_indices_by_category('thematic') + assert 'NIFTY ALPHA 50' in nse_product.get_equity_indices_by_category('strategy') + assert 'NIFTY50 USD' in nse_product.get_equity_indices_by_category('variant') + + # error test + with pytest.raises(Exception) as exc_info: + nse_product.get_equity_indices_by_category('region') + assert exc_info.value.args[0] == message['error_category'] + + +def test_is_index_exist( + nse_product +): + + assert nse_product.is_index_exist('NIFTY 100') is True + assert nse_product.is_index_exist('INVALID') is False + + +def test_get_equity_index_base_date( + nse_product, + message +): + + # pass test + assert nse_product.get_equity_index_base_date('NIFTY100 EQUAL WEIGHT') == '01-Jan-2003' + assert nse_product.get_equity_index_base_date('NIFTY INDIA DEFENCE') == '02-Apr-2018' + + # error test + with pytest.raises(Exception) as exc_info: + nse_product.get_equity_index_base_date('INVALID') + assert exc_info.value.args[0] == message['error_index1'] + + +def test_get_equity_index_base_value( + nse_product, + message +): + + # pass test + assert nse_product.get_equity_index_base_value('NIFTY MIDCAP LIQUID 15') == 1500.0 + assert nse_product.get_equity_index_base_value('NIFTY IT') == 100.0 + + # error test + with pytest.raises(Exception) as exc_info: + nse_product.get_equity_index_base_value('INVALID') + assert exc_info.value.args[0] == message['error_index1'] + + +def test_is_index_data_open_source( + nse_tri, + message +): + + # pass test + assert nse_tri.is_index_open_source('NIFTY 50') is True + assert nse_tri.is_index_open_source('NIFTY50 USD') is False + + # error test + with pytest.raises(Exception) as exc_info: + nse_tri.is_index_open_source('INVALID') + assert exc_info.value.args[0] == message['error_index1'] + + +def test_download_historical_daily_data( + nse_tri, + message +): + + # error test for non open-source index + with pytest.raises(Exception) as exc_info: + nse_tri.download_historical_daily_data( + index='NIFTY50 USD', + start_date='27-Sep-2024', + end_date='27-Sep-2024' + ) + assert exc_info.value.args[0] == message['error_index2'] + + # error test for invalid start date input + with pytest.raises(Exception) as exc_info: + nse_tri.download_historical_daily_data( + index='NIFTY 50', + start_date='16-Sep-202', + end_date='26-Sep-2024' + ) + assert exc_info.value.args[0] == message['error_date1'] + + # error test for invalid end date input + with pytest.raises(Exception) as exc_info: + nse_tri.download_historical_daily_data( + index='NIFTY 50', + start_date='16-Sep-2024', + end_date='20-Se-2024' + ) + assert exc_info.value.args[0] == message['error_date2'] + + # error test for strat date later than end date + with pytest.raises(Exception) as exc_info: + nse_tri.download_historical_daily_data( + index='NIFTY 50', + start_date='27-Sep-2024', + end_date='26-Sep-2024' + ) + assert exc_info.value.args[0] == message['error_date3'] + + # error test for invalid Excel file input + with pytest.raises(Exception) as exc_info: + nse_tri.download_historical_daily_data( + index='NIFTY 50', + start_date='23-Sep-2024', + end_date='27-Sep-2024', + excel_file='NIFTY50_tri.xl' + ) + assert exc_info.value.args[0] == message['error_excel'] + + # pass test for saving the output DataFrame to an Excel file + with tempfile.TemporaryDirectory() as tmp_dir: + excel_file = os.path.join(tmp_dir, 'equity_index.xlsx') + nse_tri.download_historical_daily_data( + index='NIFTY 50', + start_date='23-Sep-2024', + end_date='27-Sep-2024', + excel_file=excel_file + ) + df = pandas.read_excel(excel_file) + assert float(df.iloc[-1, -1]) == 38861.64 + + # pass test for valid start and end dates + df = nse_tri.download_historical_daily_data( + index='NIFTY SMALLCAP 100', + start_date='27-Sep-2024', + end_date='27-Sep-2024' + ) + assert float(df.iloc[-1, -1]) == 24686.28 + + # pass test for start date being None + df = nse_tri.download_historical_daily_data( + index='NIFTY INDIA DEFENCE', + start_date=None, + end_date='06-Apr-2018' + ) + assert float(df.iloc[0, -1]) == 1000.00 + + # pass test for end date being None + start_date = (datetime.date.today() - datetime.timedelta(days=7)).strftime('%d-%b-%Y') + df = nse_tri.download_historical_daily_data( + index='NIFTY CONSUMER DURABLES', + start_date=start_date, + end_date=None + ) + assert len(df) > 0 + + +@pytest.mark.parametrize( + 'index, expected_value', + [ + ('NIFTY MIDCAP150 MOMENTUM 50', 82438.16), + ('NIFTY 50 FUTURES TR', 28187.74), + ] +) +def test_index_download_historical_daily_data( + nse_tri, + index, + expected_value +): + + df = nse_tri.download_historical_daily_data( + index=index, + start_date='27-Sep-2024', + end_date='27-Sep-2024' + ) + assert float(df.iloc[-1, -1]) == expected_value diff --git a/tests/test_nse_track.py b/tests/test_nse_track.py deleted file mode 100644 index 9dd60cd..0000000 --- a/tests/test_nse_track.py +++ /dev/null @@ -1,55 +0,0 @@ -import pytest -from BharatFinTrack import NSETrack - - -@pytest.fixture(scope='module') -def class_instance(): - - yield NSETrack() - - -def test_get_indices_by_category( - class_instance -): - - # pass test - assert class_instance.get_indices_by_category('broad')[0] == 'NIFTY 500' - assert 'NIFTY ALPHA 50' in class_instance.get_indices_by_category('strategy') - - # error test - with pytest.raises(Exception) as exc_info: - class_instance.get_indices_by_category('non-existence') - assert exc_info.value.args[0] == 'Invadid category: non-existence' - - -def test_is_downloadable_index( - class_instance -): - - assert class_instance.is_downloadable_index('NIFTY 100') is True - assert class_instance.is_downloadable_index('non-existence') is False - - -def test_get_index_base_date( - class_instance -): - - assert class_instance.get_index_base_date('NIFTY 50') == '03-Nov-1995' - - # error test - with pytest.raises(Exception) as exc_info: - class_instance.get_index_base_date('non-existence') - assert exc_info.value.args[0] == 'Invalid index: non-existence' - - -def test_get_index_base_value( - class_instance -): - - assert class_instance.get_index_base_value('NIFTY 500') == 1000.0 - assert class_instance.get_index_base_value('NIFTY IT') == 100.0 - - # error test - with pytest.raises(Exception) as exc_info: - class_instance.get_index_base_value('non-existence') - assert exc_info.value.args[0] == 'Invalid index: non-existence'