├── .github └── workflows │ ├── main.yml │ └── static.yml ├── .gitignore ├── .idea └── .gitignore ├── IDX_FUT.toml ├── IDX_OPT.toml ├── README.md ├── example.py ├── master.toml ├── master_generator.py ├── master_instruments.csv ├── pyproject.toml └── requirements.txt /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Master Generator 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | branches: 9 | - main 10 | schedule: 11 | - cron: '30 3,15 * * *' # Runs at 3:30 AM and 3:30 PM UTC time (8:30 AM and PM IST) 12 | 13 | jobs: 14 | build: 15 | runs-on: ubuntu-latest 16 | env: 17 | CI_COMMIT_MESSAGE: Update Latest Instruments + Config Files 18 | CI_COMMIT_AUTHOR: xcode88 19 | steps: 20 | - uses: actions/checkout@v3 21 | # Build steps 22 | - uses: actions/setup-python@v4 23 | with: 24 | python-version: '3.11.x' 25 | - run: python --version 26 | - run: pip install -r requirements.txt 27 | - run: python master_generator.py 28 | 29 | # Commit and push all changed files. 30 | - name: GIT Commit Build Artifacts (coverage, dist, devdist, docs) 31 | # Only run on main branch push (e.g. after pull request merge). 32 | if: contains(fromJson('["schedule", "push", "pull_request"]'), github.event_name) 33 | run: | 34 | git config --global user.name "${{ env.CI_COMMIT_AUTHOR }}" 35 | git config --global user.email "13439842+xcode88@users.noreply.github.com" 36 | git add --all 37 | git commit --all -m "${{ env.CI_COMMIT_MESSAGE }}" 38 | git push 39 | -------------------------------------------------------------------------------- /.github/workflows/static.yml: -------------------------------------------------------------------------------- 1 | # Simple workflow for deploying static content to GitHub Pages 2 | name: Deploy static content to Pages 3 | 4 | on: 5 | # Runs on pushes targeting the default branch 6 | push: 7 | branches: ["main"] 8 | schedule: 9 | - cron: '30 3,20 * * *' # Runs at 3:30 AM and 3:30 PM UTC time (8:30 AM and PM IST) 10 | 11 | # Allows you to run this workflow manually from the Actions tab 12 | workflow_dispatch: 13 | 14 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages 15 | permissions: 16 | contents: read 17 | pages: write 18 | id-token: write 19 | 20 | # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. 21 | # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. 22 | concurrency: 23 | group: "pages" 24 | cancel-in-progress: false 25 | 26 | jobs: 27 | # Single deploy job since we're just deploying 28 | deploy: 29 | environment: 30 | name: github-pages 31 | url: ${{ steps.deployment.outputs.page_url }} 32 | runs-on: ubuntu-latest 33 | steps: 34 | - name: Checkout 35 | uses: actions/checkout@v3 36 | - name: Setup Pages 37 | uses: actions/configure-pages@v3 38 | - name: Upload artifact 39 | uses: actions/upload-pages-artifact@v1 40 | with: 41 | # Upload entire repository 42 | path: '.' 43 | - name: Deploy to GitHub Pages 44 | id: deployment 45 | uses: actions/deploy-pages@v2 46 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | *.py,cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | cover/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | .pybuilder/ 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | # For a library or package, you might want to ignore these files since the code is 87 | # intended to run in multiple environments; otherwise, check them in: 88 | # .python-version 89 | 90 | # pipenv 91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 94 | # install all needed dependencies. 95 | #Pipfile.lock 96 | 97 | # poetry 98 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 99 | # This is especially recommended for binary packages to ensure reproducibility, and is more 100 | # commonly ignored for libraries. 101 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 102 | #poetry.lock 103 | 104 | # pdm 105 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 106 | #pdm.lock 107 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 108 | # in version control. 109 | # https://pdm.fming.dev/#use-with-ide 110 | .pdm.toml 111 | 112 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 113 | __pypackages__/ 114 | 115 | # Celery stuff 116 | celerybeat-schedule 117 | celerybeat.pid 118 | 119 | # SageMath parsed files 120 | *.sage.py 121 | 122 | # Environments 123 | .env 124 | .venv 125 | env/ 126 | venv/ 127 | ENV/ 128 | env.bak/ 129 | venv.bak/ 130 | 131 | # Spyder project settings 132 | .spyderproject 133 | .spyproject 134 | 135 | # Rope project settings 136 | .ropeproject 137 | 138 | # mkdocs documentation 139 | /site 140 | 141 | # mypy 142 | .mypy_cache/ 143 | .dmypy.json 144 | dmypy.json 145 | 146 | # Pyre type checker 147 | .pyre/ 148 | 149 | # pytype static type analyzer 150 | .pytype/ 151 | 152 | # Cython debug symbols 153 | cython_debug/ 154 | 155 | # PyCharm 156 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 157 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 158 | # and can be added to the global gitignore or merged into this file. For a more nuclear 159 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 160 | #.idea/ 161 | # poetry export --without-hashes --format=requirements.txt > requirements.txt -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | -------------------------------------------------------------------------------- /IDX_FUT.toml: -------------------------------------------------------------------------------- 1 | [[NIFTY]] 2 | tradingsymbol = "NIFTY23JUNFUT" 3 | expiry = "2023-06-29" 4 | lot_size = 50 5 | freeze_qty = 1800 6 | 7 | [[NIFTY]] 8 | tradingsymbol = "NIFTY23JULFUT" 9 | expiry = "2023-07-27" 10 | lot_size = 50 11 | freeze_qty = 1800 12 | 13 | [[NIFTY]] 14 | tradingsymbol = "NIFTY23AUGFUT" 15 | expiry = "2023-08-31" 16 | lot_size = 50 17 | freeze_qty = 1800 18 | 19 | [[BANKNIFTY]] 20 | tradingsymbol = "BANKNIFTY23JUNFUT" 21 | expiry = "2023-06-29" 22 | lot_size = 25 23 | freeze_qty = 900 24 | 25 | [[BANKNIFTY]] 26 | tradingsymbol = "BANKNIFTY23JULFUT" 27 | expiry = "2023-07-27" 28 | lot_size = 15 29 | freeze_qty = 900 30 | 31 | [[BANKNIFTY]] 32 | tradingsymbol = "BANKNIFTY23AUGFUT" 33 | expiry = "2023-08-31" 34 | lot_size = 15 35 | freeze_qty = 900 36 | 37 | [[FINNIFTY]] 38 | tradingsymbol = "FINNIFTY23JUNFUT" 39 | expiry = "2023-06-27" 40 | lot_size = 40 41 | freeze_qty = 1800 42 | 43 | [[FINNIFTY]] 44 | tradingsymbol = "FINNIFTY23JULFUT" 45 | expiry = "2023-07-25" 46 | lot_size = 40 47 | freeze_qty = 1800 48 | 49 | [[FINNIFTY]] 50 | tradingsymbol = "FINNIFTY23AUGFUT" 51 | expiry = "2023-08-29" 52 | lot_size = 40 53 | freeze_qty = 1800 54 | 55 | -------------------------------------------------------------------------------- /IDX_OPT.toml: -------------------------------------------------------------------------------- 1 | [[FINNIFTY]] 2 | expiry = "2023-06-06" 3 | lot_size = 40 4 | exp_frmt = "23606" 5 | freeze_qty = 1800 6 | 7 | [[FINNIFTY]] 8 | expiry = "2023-06-13" 9 | lot_size = 40 10 | exp_frmt = "23613" 11 | freeze_qty = 1800 12 | 13 | [[FINNIFTY]] 14 | expiry = "2023-06-20" 15 | lot_size = 40 16 | exp_frmt = "23620" 17 | freeze_qty = 1800 18 | 19 | [[FINNIFTY]] 20 | expiry = "2023-06-27" 21 | lot_size = 40 22 | exp_frmt = "23JUN" 23 | freeze_qty = 1800 24 | 25 | [[FINNIFTY]] 26 | expiry = "2023-07-04" 27 | lot_size = 40 28 | exp_frmt = "23704" 29 | freeze_qty = 1800 30 | 31 | [[FINNIFTY]] 32 | expiry = "2023-07-25" 33 | lot_size = 40 34 | exp_frmt = "23JUL" 35 | freeze_qty = 1800 36 | 37 | [[FINNIFTY]] 38 | expiry = "2023-08-29" 39 | lot_size = 40 40 | exp_frmt = "23AUG" 41 | freeze_qty = 1800 42 | 43 | [[NIFTY]] 44 | expiry = "2023-06-08" 45 | lot_size = 50 46 | exp_frmt = "23608" 47 | freeze_qty = 1800 48 | 49 | [[NIFTY]] 50 | expiry = "2023-06-15" 51 | lot_size = 50 52 | exp_frmt = "23615" 53 | freeze_qty = 1800 54 | 55 | [[NIFTY]] 56 | expiry = "2023-06-22" 57 | lot_size = 50 58 | exp_frmt = "23622" 59 | freeze_qty = 1800 60 | 61 | [[NIFTY]] 62 | expiry = "2023-06-29" 63 | lot_size = 50 64 | exp_frmt = "23JUN" 65 | freeze_qty = 1800 66 | 67 | [[NIFTY]] 68 | expiry = "2023-07-06" 69 | lot_size = 50 70 | exp_frmt = "23706" 71 | freeze_qty = 1800 72 | 73 | [[NIFTY]] 74 | expiry = "2023-07-27" 75 | lot_size = 50 76 | exp_frmt = "23JUL" 77 | freeze_qty = 1800 78 | 79 | [[NIFTY]] 80 | expiry = "2023-08-31" 81 | lot_size = 50 82 | exp_frmt = "23AUG" 83 | freeze_qty = 1800 84 | 85 | [[NIFTY]] 86 | expiry = "2023-09-28" 87 | lot_size = 50 88 | exp_frmt = "23SEP" 89 | freeze_qty = 1800 90 | 91 | [[NIFTY]] 92 | expiry = "2023-12-28" 93 | lot_size = 50 94 | exp_frmt = "23DEC" 95 | freeze_qty = 1800 96 | 97 | [[NIFTY]] 98 | expiry = "2024-03-28" 99 | lot_size = 50 100 | exp_frmt = "24MAR" 101 | freeze_qty = 1800 102 | 103 | [[NIFTY]] 104 | expiry = "2024-06-27" 105 | lot_size = 50 106 | exp_frmt = "24JUN" 107 | freeze_qty = 1800 108 | 109 | [[NIFTY]] 110 | expiry = "2024-12-26" 111 | lot_size = 50 112 | exp_frmt = "24DEC" 113 | freeze_qty = 1800 114 | 115 | [[NIFTY]] 116 | expiry = "2025-06-26" 117 | lot_size = 50 118 | exp_frmt = "25JUN" 119 | freeze_qty = 1800 120 | 121 | [[NIFTY]] 122 | expiry = "2025-12-24" 123 | lot_size = 50 124 | exp_frmt = "25DEC" 125 | freeze_qty = 1800 126 | 127 | [[NIFTY]] 128 | expiry = "2026-06-25" 129 | lot_size = 50 130 | exp_frmt = "26JUN" 131 | freeze_qty = 1800 132 | 133 | [[NIFTY]] 134 | expiry = "2026-12-31" 135 | lot_size = 50 136 | exp_frmt = "26DEC" 137 | freeze_qty = 1800 138 | 139 | [[NIFTY]] 140 | expiry = "2027-06-24" 141 | lot_size = 50 142 | exp_frmt = "27JUN" 143 | freeze_qty = 1800 144 | 145 | [[NIFTY]] 146 | expiry = "2027-12-30" 147 | lot_size = 50 148 | exp_frmt = "27DEC" 149 | freeze_qty = 1800 150 | 151 | [[BANKNIFTY]] 152 | expiry = "2023-06-08" 153 | lot_size = 25 154 | exp_frmt = "23608" 155 | freeze_qty = 900 156 | 157 | [[BANKNIFTY]] 158 | expiry = "2023-06-15" 159 | lot_size = 25 160 | exp_frmt = "23615" 161 | freeze_qty = 900 162 | 163 | [[BANKNIFTY]] 164 | expiry = "2023-06-22" 165 | lot_size = 25 166 | exp_frmt = "23622" 167 | freeze_qty = 900 168 | 169 | [[BANKNIFTY]] 170 | expiry = "2023-06-29" 171 | lot_size = 25 172 | exp_frmt = "23JUN" 173 | freeze_qty = 900 174 | 175 | [[BANKNIFTY]] 176 | expiry = "2023-07-06" 177 | lot_size = 25 178 | exp_frmt = "23706" 179 | freeze_qty = 900 180 | 181 | [[BANKNIFTY]] 182 | expiry = "2023-07-27" 183 | lot_size = 15 184 | exp_frmt = "23JUL" 185 | freeze_qty = 900 186 | 187 | [[BANKNIFTY]] 188 | expiry = "2023-08-31" 189 | lot_size = 15 190 | exp_frmt = "23AUG" 191 | freeze_qty = 900 192 | 193 | [[BANKNIFTY]] 194 | expiry = "2023-09-28" 195 | lot_size = 25 196 | exp_frmt = "23SEP" 197 | freeze_qty = 900 198 | 199 | [[BANKNIFTY]] 200 | expiry = "2023-12-28" 201 | lot_size = 25 202 | exp_frmt = "23DEC" 203 | freeze_qty = 900 204 | 205 | [[BANKNIFTY]] 206 | expiry = "2024-03-28" 207 | lot_size = 25 208 | exp_frmt = "24MAR" 209 | freeze_qty = 900 210 | 211 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Prerequisites 3 | 4 | A rough-and-ready method to set up some config files ahead of open. 5 | 6 | These files will help us smoothly deal with freeze quantities and lot sizes for different indices based on their expiries. 7 | 8 | [IDX_FUT.toml](https://xcode88.github.io/fno-pre-req/IDX_FUT.toml) 9 | 10 | [IDX_OPT.toml](https://xcode88.github.io/fno-pre-req/IDX_OPT.toml) 11 | 12 | The above files are scheduled to be updated every morning 8:30 AM. You can use them by simply downloading and storing them somwhere in your project structure. 13 | 14 | 15 | 16 | ## Usage/Examples 17 | 18 | Example snippet on downloading files from urls. 19 | 20 | ```python 21 | def download_file_as(file_url: str, save_as_name: str): 22 | try: 23 | response = request.urlretrieve(file_url, save_as_name) 24 | print(response) 25 | except Exception as E: 26 | print(E) 27 | 28 | 29 | download_file_as("https://xcode88.github.io/fno-pre-req/IDX_FUT.toml", "IDX_FUT.toml") 30 | download_file_as("https://xcode88.github.io/fno-pre-req/IDX_OPT.toml", "IDX_OPT.toml") 31 | ``` 32 | 33 | Example snippet on loading configurations from TOML 34 | ```python 35 | 36 | import toml 37 | from typing import Optional, Dict, Any 38 | 39 | 40 | def load_configurations(file_path) -> Optional[Dict[str, Any]]: 41 | try: 42 | with open(file_path, 'r') as file: 43 | config = toml.load(file) 44 | return config 45 | except FileNotFoundError as FFE: 46 | print(f"{FFE.__str__()}") 47 | return None 48 | except Exception as E: 49 | print(f"{E.__str__()}") 50 | return None 51 | ``` 52 | 53 | For Index Futures 54 | ```python 55 | 56 | index_FUT = load_configurations(file_path="IDX_FUT.toml") 57 | 58 | print(index_FUT) 59 | 60 | ``` 61 | Result 62 | ```javascript 63 | { 64 | "NIFTY":[ 65 | { 66 | "tradingsymbol":"NIFTY23JUNFUT", 67 | "expiry":"2023-06-29", 68 | "lot_size":50, 69 | "freeze_qty":1800 70 | }, 71 | { 72 | "tradingsymbol":"NIFTY23JULFUT", 73 | "expiry":"2023-07-27", 74 | "lot_size":50, 75 | "freeze_qty":1800 76 | }, 77 | { 78 | "tradingsymbol":"NIFTY23AUGFUT", 79 | "expiry":"2023-08-31", 80 | "lot_size":50, 81 | "freeze_qty":1800 82 | } 83 | ], 84 | "BANKNIFTY":[ 85 | { 86 | "tradingsymbol":"BANKNIFTY23JUNFUT", 87 | "expiry":"2023-06-29", 88 | "lot_size":25, 89 | "freeze_qty":900 90 | }, 91 | { 92 | "tradingsymbol":"BANKNIFTY23JULFUT", 93 | "expiry":"2023-07-27", 94 | "lot_size":15, 95 | "freeze_qty":900 96 | }, 97 | { 98 | "tradingsymbol":"BANKNIFTY23AUGFUT", 99 | "expiry":"2023-08-31", 100 | "lot_size":15, 101 | "freeze_qty":900 102 | } 103 | ], 104 | "FINNIFTY":[ 105 | { 106 | "tradingsymbol":"FINNIFTY23JUNFUT", 107 | "expiry":"2023-06-27", 108 | "lot_size":40, 109 | "freeze_qty":1800 110 | }, 111 | { 112 | "tradingsymbol":"FINNIFTY23JULFUT", 113 | "expiry":"2023-07-25", 114 | "lot_size":40, 115 | "freeze_qty":1800 116 | }, 117 | { 118 | "tradingsymbol":"FINNIFTY23AUGFUT", 119 | "expiry":"2023-08-29", 120 | "lot_size":40, 121 | "freeze_qty":1800 122 | } 123 | ] 124 | } 125 | 126 | ``` 127 | For Index Options 128 | ```python 129 | 130 | index_OPT = load_configurations(file_path="IDX_OPT.toml") 131 | print(index_OPT) 132 | 133 | ``` 134 | Result 135 | ```javascript 136 | { 137 | "FINNIFTY":[ 138 | { 139 | "expiry":"2023-06-06", 140 | "lot_size":40, 141 | "exp_frmt":"23606", 142 | "freeze_qty":1800 143 | }, 144 | { 145 | "expiry":"2023-06-13", 146 | "lot_size":40, 147 | "exp_frmt":"23613", 148 | "freeze_qty":1800 149 | }, 150 | { 151 | "expiry":"2023-06-20", 152 | "lot_size":40, 153 | "exp_frmt":"23620", 154 | "freeze_qty":1800 155 | }, 156 | { 157 | "expiry":"2023-06-27", 158 | "lot_size":40, 159 | "exp_frmt":"23JUN", 160 | "freeze_qty":1800 161 | }, 162 | { 163 | "expiry":"2023-07-04", 164 | "lot_size":40, 165 | "exp_frmt":"23704", 166 | "freeze_qty":1800 167 | }, 168 | { 169 | "expiry":"2023-07-25", 170 | "lot_size":40, 171 | "exp_frmt":"23JUL", 172 | "freeze_qty":1800 173 | }, 174 | { 175 | "expiry":"2023-08-29", 176 | "lot_size":40, 177 | "exp_frmt":"23AUG", 178 | "freeze_qty":1800 179 | } 180 | ], 181 | "NIFTY":[ 182 | { 183 | "expiry":"2023-06-08", 184 | "lot_size":50, 185 | "exp_frmt":"23608", 186 | "freeze_qty":1800 187 | }, 188 | { 189 | "expiry":"2023-06-15", 190 | "lot_size":50, 191 | "exp_frmt":"23615", 192 | "freeze_qty":1800 193 | }, 194 | { 195 | "expiry":"2023-06-22", 196 | "lot_size":50, 197 | "exp_frmt":"23622", 198 | "freeze_qty":1800 199 | }, 200 | { 201 | "expiry":"2023-06-29", 202 | "lot_size":50, 203 | "exp_frmt":"23JUN", 204 | "freeze_qty":1800 205 | }, 206 | { 207 | "expiry":"2023-07-06", 208 | "lot_size":50, 209 | "exp_frmt":"23706", 210 | "freeze_qty":1800 211 | }, 212 | { 213 | "expiry":"2023-07-27", 214 | "lot_size":50, 215 | "exp_frmt":"23JUL", 216 | "freeze_qty":1800 217 | }, 218 | { 219 | "expiry":"2023-08-31", 220 | "lot_size":50, 221 | "exp_frmt":"23AUG", 222 | "freeze_qty":1800 223 | }, 224 | { 225 | "expiry":"2023-09-28", 226 | "lot_size":50, 227 | "exp_frmt":"23SEP", 228 | "freeze_qty":1800 229 | }, 230 | { 231 | "expiry":"2023-12-28", 232 | "lot_size":50, 233 | "exp_frmt":"23DEC", 234 | "freeze_qty":1800 235 | }, 236 | { 237 | "expiry":"2024-03-28", 238 | "lot_size":50, 239 | "exp_frmt":"24MAR", 240 | "freeze_qty":1800 241 | }, 242 | { 243 | "expiry":"2024-06-27", 244 | "lot_size":50, 245 | "exp_frmt":"24JUN", 246 | "freeze_qty":1800 247 | }, 248 | { 249 | "expiry":"2024-12-26", 250 | "lot_size":50, 251 | "exp_frmt":"24DEC", 252 | "freeze_qty":1800 253 | }, 254 | { 255 | "expiry":"2025-06-26", 256 | "lot_size":50, 257 | "exp_frmt":"25JUN", 258 | "freeze_qty":1800 259 | }, 260 | { 261 | "expiry":"2025-12-24", 262 | "lot_size":50, 263 | "exp_frmt":"25DEC", 264 | "freeze_qty":1800 265 | }, 266 | { 267 | "expiry":"2026-06-25", 268 | "lot_size":50, 269 | "exp_frmt":"26JUN", 270 | "freeze_qty":1800 271 | }, 272 | { 273 | "expiry":"2026-12-31", 274 | "lot_size":50, 275 | "exp_frmt":"26DEC", 276 | "freeze_qty":1800 277 | }, 278 | { 279 | "expiry":"2027-06-24", 280 | "lot_size":50, 281 | "exp_frmt":"27JUN", 282 | "freeze_qty":1800 283 | }, 284 | { 285 | "expiry":"2027-12-30", 286 | "lot_size":50, 287 | "exp_frmt":"27DEC", 288 | "freeze_qty":1800 289 | } 290 | ], 291 | "BANKNIFTY":[ 292 | { 293 | "expiry":"2023-06-08", 294 | "lot_size":25, 295 | "exp_frmt":"23608", 296 | "freeze_qty":900 297 | }, 298 | { 299 | "expiry":"2023-06-15", 300 | "lot_size":25, 301 | "exp_frmt":"23615", 302 | "freeze_qty":900 303 | }, 304 | { 305 | "expiry":"2023-06-22", 306 | "lot_size":25, 307 | "exp_frmt":"23622", 308 | "freeze_qty":900 309 | }, 310 | { 311 | "expiry":"2023-06-29", 312 | "lot_size":25, 313 | "exp_frmt":"23JUN", 314 | "freeze_qty":900 315 | }, 316 | { 317 | "expiry":"2023-07-06", 318 | "lot_size":25, 319 | "exp_frmt":"23706", 320 | "freeze_qty":900 321 | }, 322 | { 323 | "expiry":"2023-07-27", 324 | "lot_size":15, 325 | "exp_frmt":"23JUL", 326 | "freeze_qty":900 327 | }, 328 | { 329 | "expiry":"2023-08-31", 330 | "lot_size":15, 331 | "exp_frmt":"23AUG", 332 | "freeze_qty":900 333 | }, 334 | { 335 | "expiry":"2023-09-28", 336 | "lot_size":25, 337 | "exp_frmt":"23SEP", 338 | "freeze_qty":900 339 | }, 340 | { 341 | "expiry":"2023-12-28", 342 | "lot_size":25, 343 | "exp_frmt":"23DEC", 344 | "freeze_qty":900 345 | }, 346 | { 347 | "expiry":"2024-03-28", 348 | "lot_size":25, 349 | "exp_frmt":"24MAR", 350 | "freeze_qty":900 351 | } 352 | ] 353 | } 354 | 355 | ``` 356 | 357 | Once you have the above it is upto you how you want to use them, easiest way is to write a couple of wrapper with functions to extract information for a particular instrument and expiry. 358 | -------------------------------------------------------------------------------- /example.py: -------------------------------------------------------------------------------- 1 | import toml 2 | from typing import Optional, Dict, Any 3 | from urllib import request 4 | 5 | 6 | def download_file_as(file_url: str, save_as_name: str): 7 | try: 8 | response = request.urlretrieve(file_url, save_as_name) 9 | print(response) 10 | except Exception as E: 11 | print(E) 12 | 13 | 14 | download_file_as("https://xcode88.github.io/fno-pre-req/IDX_FUT.toml", "IDX_FUT.toml") 15 | download_file_as("https://xcode88.github.io/fno-pre-req/IDX_OPT.toml", "IDX_OPT.toml") 16 | 17 | 18 | def load_configurations(file_path) -> Optional[Dict[str, Any]]: 19 | """ Load Configurations from downloaded toml """ 20 | try: 21 | with open(file_path, 'r') as file: 22 | config = toml.load(file) 23 | return config 24 | except FileNotFoundError as FFE: 25 | print(f"{FFE.__str__()}") 26 | return None 27 | except Exception as E: 28 | print(f"{E.__str__()}") 29 | return None 30 | 31 | 32 | index_FUT = load_configurations(file_path="IDX_FUT.toml") 33 | index_OPT = load_configurations(file_path="IDX_OPT.toml") 34 | 35 | print(index_FUT) 36 | print(index_OPT) 37 | -------------------------------------------------------------------------------- /master.toml: -------------------------------------------------------------------------------- 1 | generated_timestamp = "2023-06-04 14:54:04.252808" 2 | -------------------------------------------------------------------------------- /master_generator.py: -------------------------------------------------------------------------------- 1 | import datetime as dt 2 | import os 3 | from pathlib import Path 4 | from pprint import pprint 5 | from typing import Union, Dict 6 | 7 | import pandas as pd 8 | import toml 9 | import logging 10 | 11 | DEV_MODE = False 12 | 13 | logger = logging.getLogger(__name__) 14 | 15 | logger.setLevel(logging.INFO) 16 | 17 | console_handler = logging.StreamHandler() 18 | console_handler.setLevel(logging.INFO) 19 | 20 | file_handler = logging.FileHandler('execution.log') 21 | file_handler.setLevel(logging.INFO) 22 | 23 | formatter = logging.Formatter('%(asctime)s | %(levelname)s | %(name)s | %(filename)s:%(lineno)d | %(message)s') 24 | console_handler.setFormatter(formatter) 25 | file_handler.setFormatter(formatter) 26 | if DEV_MODE: 27 | logger.addHandler(console_handler) 28 | logger.addHandler(file_handler) 29 | 30 | 31 | class FNOPR: 32 | def __init__(self): 33 | self.INSTRUMENTS_URL = "https://api.kite.trade/instruments/NFO" 34 | self.NSE_FREEZE_QTY_URL = "https://archives.nseindia.com/content/fo/qtyfreeze.xls" 35 | self.INSTRUMENT_FILENAME = "master_instruments.csv" 36 | self.MASTER_FILENAME = "master.toml" 37 | self.FUT_FILENAME = "IDX_FUT.toml" 38 | self.OPTIONS_FILENAME = "IDX_OPT.toml" 39 | self.INDICES = ["NIFTY", "BANKNIFTY", "FINNIFTY"] 40 | self.FREEZE_QTY = self.get_freeze_quantity() 41 | 42 | if self.last_update(): 43 | self.download_latest_file() 44 | else: 45 | print(f"Instrument File already up to date. Proceed further.") 46 | logging.info(f"Instrument File already up to date. Proceed further.") 47 | 48 | self.get_index_futures_info() 49 | self.get_index_options_info() 50 | 51 | def download_latest_file(self) -> None: 52 | try: 53 | df = pd.read_csv(self.INSTRUMENTS_URL) 54 | df.to_csv(self.INSTRUMENT_FILENAME) 55 | 56 | timestamp = dt.datetime.now() 57 | data = {"generated_timestamp": str(timestamp)} 58 | self.write_master(self.MASTER_FILENAME, toml_data=data) 59 | logger.info(f"Instruments File downloaded successfully.") 60 | 61 | except OSError as OSE: 62 | logger.exception(OSE) 63 | except RuntimeError as RE: 64 | logger.exception(RE) 65 | except Exception as E: 66 | logger.exception(E) 67 | 68 | @staticmethod 69 | def read_master( 70 | master_file_path: Union[str, Path] 71 | ): 72 | try: 73 | with open(master_file_path, "r") as f: 74 | master_data = toml.load(f) 75 | return master_data 76 | except FileNotFoundError: 77 | logger.error(f"{master_file_path} not found.") 78 | return None 79 | except Exception as E: 80 | logger.exception(E) 81 | return None 82 | 83 | @staticmethod 84 | def write_master( 85 | master_file_path: Union[str, Path], 86 | toml_data: Dict 87 | ) -> None: 88 | try: 89 | with open(master_file_path, "w") as f: 90 | toml.dump(toml_data, f) 91 | logger.info(f"{master_file_path} prepared successfully.") 92 | except Exception as E: 93 | logger.exception(E) 94 | 95 | @staticmethod 96 | def update_master( 97 | master_file_path: Union[str, Path], 98 | data_list: Dict 99 | ) -> None: 100 | try: 101 | toml_data = FNOPR.read_master(master_file_path) 102 | if toml_data is not None: 103 | toml_data.update(data_list) 104 | FNOPR.write_master(master_file_path, toml_data) 105 | except Exception as E: 106 | logger.exception(E) 107 | 108 | def last_update(self) -> bool: 109 | try: 110 | data = self.read_master(self.MASTER_FILENAME) 111 | if data is not None: 112 | given_timestamp = dt.datetime.strptime(data["generated_timestamp"], '%Y-%m-%d %H:%M:%S.%f') 113 | current_time = dt.datetime.now() 114 | time_difference = current_time - given_timestamp 115 | return time_difference >= dt.timedelta(hours=12) 116 | else: 117 | return True 118 | 119 | except ValueError as VE: 120 | logger.error(f"Invalid Time Format {VE.__str__()}") 121 | return False 122 | except Exception as E: 123 | logger.exception(E) 124 | return True 125 | 126 | def get_index_futures_info(self) -> None: 127 | try: 128 | data = pd.read_csv(self.INSTRUMENT_FILENAME) 129 | 130 | df = data.query("segment == 'NFO-FUT' and name in @self.INDICES")[ 131 | ["name", "tradingsymbol", "expiry", "lot_size"]] 132 | df['freeze_qty'] = df['name'].map(self.FREEZE_QTY) 133 | 134 | result = { 135 | name: sorted([ 136 | { 137 | 'tradingsymbol': trading_symbol, 138 | 'expiry': expiry, 139 | 'lot_size': lot_size, 140 | 'freeze_qty': freeze_qty 141 | } 142 | for trading_symbol, expiry, lot_size, freeze_qty in zip( 143 | df[df['name'] == name]['tradingsymbol'], 144 | df[df['name'] == name]['expiry'], 145 | df[df['name'] == name]['lot_size'], 146 | df[df['name'] == name]['freeze_qty'] 147 | ) 148 | ], 149 | key=lambda r: r["expiry"] 150 | ) 151 | for name in df['name'].unique() 152 | } 153 | 154 | self.write_master(self.FUT_FILENAME, toml_data=result) 155 | except Exception as E: 156 | logger.exception(E) 157 | 158 | def get_index_options_info(self) -> None: 159 | try: 160 | data = pd.read_csv(self.INSTRUMENT_FILENAME) 161 | df = data.query("segment == 'NFO-OPT' and name in @self.INDICES")[ 162 | ["name", "tradingsymbol", "expiry", "lot_size"]].drop_duplicates(subset=["name", "expiry"], 163 | keep="first").sort_values("expiry") 164 | df['freeze_qty'] = df['name'].map(self.FREEZE_QTY) 165 | df['exp_frmt'] = df.apply(lambda row: row['tradingsymbol'].replace(row['name'], '')[:5], axis=1) 166 | df.drop('tradingsymbol', axis=1, inplace=True) 167 | 168 | result = { 169 | name: sorted([ 170 | { 171 | 'expiry': expiry, 172 | 'lot_size': lot_size, 173 | 'exp_frmt': exp_frmt, 174 | 'freeze_qty': freeze_qty 175 | 176 | } 177 | for expiry, lot_size, exp_frmt, freeze_qty in zip( 178 | df[df['name'] == name]['expiry'], 179 | df[df['name'] == name]['lot_size'], 180 | df[df['name'] == name]['exp_frmt'], 181 | df[df['name'] == name]['freeze_qty'] 182 | ) 183 | ], 184 | key=lambda x: x["expiry"] 185 | ) 186 | for name in df['name'].unique() 187 | } 188 | 189 | self.write_master(self.OPTIONS_FILENAME, toml_data=result) 190 | except Exception as E: 191 | logger.exception(E) 192 | 193 | def get_freeze_quantity(self): 194 | try: 195 | df = pd.read_excel(self.NSE_FREEZE_QTY_URL, index_col=0) 196 | df.columns = df.columns.str.replace(' ', '') 197 | df["SYMBOL"] = df["SYMBOL"].str.strip() 198 | df = df.query("SYMBOL in @self.INDICES") 199 | return df.set_index('SYMBOL')['VOL_FRZ_QTY'].to_dict() 200 | 201 | except Exception as E: 202 | logger.error(f"Freeze Quantity Fetch Failed {E.__str__()}") 203 | 204 | 205 | if __name__ == '__main__': 206 | FNOPR = FNOPR() 207 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "fno-pre-req" 3 | version = "0.1.0" 4 | description = "" 5 | authors = ["pawant <13439842+xcode88@users.noreply.github.com>"] 6 | readme = "README.md" 7 | packages = [{include = "fno_pre_req"}] 8 | 9 | [tool.poetry.dependencies] 10 | python = "^3.11" 11 | toml = "^0.10.2" 12 | pandas = "^2.0.2" 13 | xlrd = "^2.0.1" 14 | 15 | 16 | [build-system] 17 | requires = ["poetry-core"] 18 | build-backend = "poetry.core.masonry.api" 19 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | numpy 2 | pandas 3 | python-dateutil 4 | pytz 5 | six 6 | toml 7 | tzdata 8 | xlrd 9 | --------------------------------------------------------------------------------