├── docs ├── .nojekyll ├── _build │ ├── _static │ │ ├── custom.css │ │ ├── file.png │ │ ├── plus.png │ │ ├── minus.png │ │ ├── styles │ │ │ └── theme.css │ │ ├── vendor │ │ │ └── fontawesome │ │ │ │ └── webfonts │ │ │ │ ├── fa-brands-400.ttf │ │ │ │ ├── fa-solid-900.ttf │ │ │ │ ├── fa-brands-400.woff2 │ │ │ │ ├── fa-regular-400.ttf │ │ │ │ ├── fa-regular-400.woff2 │ │ │ │ └── fa-solid-900.woff2 │ │ ├── graphviz.css │ │ ├── scripts │ │ │ ├── fontawesome.js.LICENSE.txt │ │ │ ├── bootstrap.js.LICENSE.txt │ │ │ └── pydata-sphinx-theme.js │ │ ├── check-solid.svg │ │ ├── documentation_options.js │ │ ├── copy-button.svg │ │ ├── github-banner.svg │ │ ├── webpack-macros.html │ │ ├── copybutton.css │ │ ├── copybutton_funcs.js │ │ ├── doctools.js │ │ ├── language_data.js │ │ ├── pygments.css │ │ ├── sphinx_highlight.js │ │ ├── clipboard.min.js │ │ ├── copybutton.js │ │ └── alabaster.css │ ├── objects.inv │ ├── .doctrees │ │ ├── index.doctree │ │ └── autoapi │ │ │ ├── index.doctree │ │ │ └── codalpy │ │ │ ├── index.doctree │ │ │ ├── codal │ │ │ └── index.doctree │ │ │ └── models │ │ │ └── index.doctree │ ├── .buildinfo │ ├── .buildinfo.bak │ ├── _sources │ │ ├── autoapi │ │ │ ├── index.rst.txt │ │ │ └── codalpy │ │ │ │ ├── codal │ │ │ │ └── index.rst.txt │ │ │ │ └── index.rst.txt │ │ └── index.rst.txt │ ├── searchindex.js │ ├── _modules │ │ └── index.html │ ├── search.html │ ├── py-modindex.html │ ├── index.html │ └── autoapi │ │ └── index.html ├── index.html ├── index.rst ├── Makefile ├── make.bat └── conf.py ├── tests └── __init__.py ├── .python-version ├── codalpy ├── utils │ ├── __init__.py │ ├── http.py │ ├── utils.py │ ├── cols.py │ ├── query.py │ ├── fund.py │ ├── gen_df.py │ └── dicts.py ├── __init__.py ├── models.py └── codal.py ├── .gitignore ├── settings.json ├── .pre-commit-config.yaml ├── pyproject.toml ├── LICENSE.txt └── README.md /docs/.nojekyll: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.python-version: -------------------------------------------------------------------------------- 1 | 3.12 2 | -------------------------------------------------------------------------------- /codalpy/utils/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/_build/_static/custom.css: -------------------------------------------------------------------------------- 1 | /* This file intentionally left blank. */ 2 | -------------------------------------------------------------------------------- /docs/_build/objects.inv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yghaderi/codalpy/HEAD/docs/_build/objects.inv -------------------------------------------------------------------------------- /docs/_build/_static/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yghaderi/codalpy/HEAD/docs/_build/_static/file.png -------------------------------------------------------------------------------- /docs/_build/_static/plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yghaderi/codalpy/HEAD/docs/_build/_static/plus.png -------------------------------------------------------------------------------- /docs/_build/_static/minus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yghaderi/codalpy/HEAD/docs/_build/_static/minus.png -------------------------------------------------------------------------------- /docs/_build/.doctrees/index.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yghaderi/codalpy/HEAD/docs/_build/.doctrees/index.doctree -------------------------------------------------------------------------------- /docs/_build/.doctrees/autoapi/index.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yghaderi/codalpy/HEAD/docs/_build/.doctrees/autoapi/index.doctree -------------------------------------------------------------------------------- /docs/_build/_static/styles/theme.css: -------------------------------------------------------------------------------- 1 | /* Provided by Sphinx's 'basic' theme, and included in the final set of assets */ 2 | @import "../basic.css"; 3 | -------------------------------------------------------------------------------- /codalpy/__init__.py: -------------------------------------------------------------------------------- 1 | from codalpy.codal import Codal 2 | from codalpy.utils.issuer import IssuerCategory 3 | 4 | __all__ = ["Codal", "IssuerCategory"] 5 | -------------------------------------------------------------------------------- /docs/_build/.doctrees/autoapi/codalpy/index.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yghaderi/codalpy/HEAD/docs/_build/.doctrees/autoapi/codalpy/index.doctree -------------------------------------------------------------------------------- /docs/_build/.doctrees/autoapi/codalpy/codal/index.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yghaderi/codalpy/HEAD/docs/_build/.doctrees/autoapi/codalpy/codal/index.doctree -------------------------------------------------------------------------------- /docs/_build/.doctrees/autoapi/codalpy/models/index.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yghaderi/codalpy/HEAD/docs/_build/.doctrees/autoapi/codalpy/models/index.doctree -------------------------------------------------------------------------------- /docs/_build/_static/vendor/fontawesome/webfonts/fa-brands-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yghaderi/codalpy/HEAD/docs/_build/_static/vendor/fontawesome/webfonts/fa-brands-400.ttf -------------------------------------------------------------------------------- /docs/_build/_static/vendor/fontawesome/webfonts/fa-solid-900.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yghaderi/codalpy/HEAD/docs/_build/_static/vendor/fontawesome/webfonts/fa-solid-900.ttf -------------------------------------------------------------------------------- /docs/_build/_static/vendor/fontawesome/webfonts/fa-brands-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yghaderi/codalpy/HEAD/docs/_build/_static/vendor/fontawesome/webfonts/fa-brands-400.woff2 -------------------------------------------------------------------------------- /docs/_build/_static/vendor/fontawesome/webfonts/fa-regular-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yghaderi/codalpy/HEAD/docs/_build/_static/vendor/fontawesome/webfonts/fa-regular-400.ttf -------------------------------------------------------------------------------- /docs/_build/_static/vendor/fontawesome/webfonts/fa-regular-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yghaderi/codalpy/HEAD/docs/_build/_static/vendor/fontawesome/webfonts/fa-regular-400.woff2 -------------------------------------------------------------------------------- /docs/_build/_static/vendor/fontawesome/webfonts/fa-solid-900.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yghaderi/codalpy/HEAD/docs/_build/_static/vendor/fontawesome/webfonts/fa-solid-900.woff2 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Python-generated files 2 | __pycache__/ 3 | *.py[oc] 4 | build/ 5 | dist/ 6 | wheels/ 7 | *.egg-info 8 | 9 | # Virtual environments 10 | .venv 11 | dev.py 12 | .env 13 | -------------------------------------------------------------------------------- /settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "jupyter": { 3 | "kernel_selections": { 4 | "python3": "deno", 5 | "typescript": "deno", 6 | "javascript": "deno" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /docs/_build/_static/graphviz.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Sphinx stylesheet -- graphviz extension. 3 | */ 4 | 5 | img.graphviz { 6 | border: 0; 7 | max-width: 100%; 8 | } 9 | 10 | object.graphviz { 11 | max-width: 100%; 12 | } 13 | -------------------------------------------------------------------------------- /docs/_build/.buildinfo: -------------------------------------------------------------------------------- 1 | # Sphinx build info version 1 2 | # This file records the configuration used when building these files. When it is not found, a full rebuild will be done. 3 | config: c6334e523093dffc92409cdca1f56d18 4 | tags: 645f666f9bcd5a90fca523b33c5a78b7 5 | -------------------------------------------------------------------------------- /docs/_build/.buildinfo.bak: -------------------------------------------------------------------------------- 1 | # Sphinx build info version 1 2 | # This file records the configuration used when building these files. When it is not found, a full rebuild will be done. 3 | config: f7a9133f7b7543e0d9b2a030f93770a6 4 | tags: 645f666f9bcd5a90fca523b33c5a78b7 5 | -------------------------------------------------------------------------------- /docs/_build/_static/scripts/fontawesome.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com 3 | * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) 4 | * Copyright 2024 Fonticons, Inc. 5 | */ 6 | -------------------------------------------------------------------------------- /docs/_build/_static/scripts/bootstrap.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v5.3.3 (https://getbootstrap.com/) 3 | * Copyright 2011-2024 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) 5 | */ 6 | -------------------------------------------------------------------------------- /docs/_build/_sources/autoapi/index.rst.txt: -------------------------------------------------------------------------------- 1 | API Reference 2 | ============= 3 | 4 | This page contains auto-generated API reference documentation [#f1]_. 5 | 6 | .. toctree:: 7 | :titlesonly: 8 | 9 | /autoapi/codalpy/index 10 | 11 | .. [#f1] Created with `sphinx-autoapi `_ 12 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | codalpy 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/_build/_static/check-solid.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /docs/_build/_static/documentation_options.js: -------------------------------------------------------------------------------- 1 | const DOCUMENTATION_OPTIONS = { 2 | VERSION: '0.4.0', 3 | LANGUAGE: 'en', 4 | COLLAPSE_INDEX: false, 5 | BUILDER: 'html', 6 | FILE_SUFFIX: '.html', 7 | LINK_SUFFIX: '.html', 8 | HAS_SOURCE: true, 9 | SOURCELINK_SUFFIX: '.txt', 10 | NAVIGATION_WITH_KEYS: false, 11 | SHOW_SEARCH_SUMMARY: true, 12 | ENABLE_SEARCH_SHORTCUTS: true, 13 | }; 14 | -------------------------------------------------------------------------------- /docs/_build/_static/copy-button.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /docs/_build/_static/github-banner.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/pre-commit/pre-commit-hooks 3 | rev: v2.3.0 4 | hooks: 5 | - id: check-yaml 6 | - id: end-of-file-fixer 7 | - id: trailing-whitespace 8 | stages: [pre-push] 9 | - repo: https://github.com/psf/black 10 | rev: 25.1.0 11 | hooks: 12 | - id: black 13 | stages: [pre-push] 14 | exclude: ^docs/ 15 | - repo: https://github.com/PyCQA/isort 16 | rev: 6.0.1 17 | hooks: 18 | - id: isort 19 | stages: [pre-push] 20 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. codalpy documentation master file, created by 2 | sphinx-quickstart on Mon Sep 15 22:44:49 2025. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | codalpy documentation 7 | ===================== 8 | 9 | Add your content using ``reStructuredText`` syntax. See the 10 | `reStructuredText `_ 11 | documentation for details. 12 | 13 | 14 | .. toctree:: 15 | :maxdepth: 2 16 | :caption: Contents: 17 | -------------------------------------------------------------------------------- /docs/_build/_sources/index.rst.txt: -------------------------------------------------------------------------------- 1 | .. codalpy documentation master file, created by 2 | sphinx-quickstart on Mon Sep 15 22:44:49 2025. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | codalpy documentation 7 | ===================== 8 | 9 | Add your content using ``reStructuredText`` syntax. See the 10 | `reStructuredText `_ 11 | documentation for details. 12 | 13 | 14 | .. toctree:: 15 | :maxdepth: 2 16 | :caption: Contents: 17 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "codalpy" 3 | version = "0.4.5" 4 | description = "Add your description here" 5 | readme = "README.md" 6 | requires-python = ">=3.12" 7 | dependencies = [ 8 | "beautifulsoup4>=4.13.4", 9 | "fastexcel>=0.13.0", 10 | "jdatetime>=5.2.0", 11 | "polars>=1.27.1", 12 | "pyarrow>=19.0.1", 13 | "pydantic>=2.10.6", 14 | "requests>=2.32.3", 15 | "tqdm>=4.67.1", 16 | ] 17 | 18 | [tool.pyright] 19 | root = "valpy" 20 | venvPath = "." 21 | venv = ".venv" 22 | 23 | [dependency-groups] 24 | dev = [ 25 | "black>=25.1.0", 26 | "ipykernel>=6.29.5", 27 | "isort>=6.0.1", 28 | "pandas>=2.3.1", 29 | "pre-commit>=4.2.0", 30 | "psycopg2-binary>=2.9.10", 31 | "pydata-sphinx-theme>=0.16.1", 32 | "sphinx-autoapi>=3.6.0", 33 | "sphinx-copybutton>=0.5.2", 34 | "sqlalchemy>=2.0.42", 35 | ] 36 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | 13 | %SPHINXBUILD% >NUL 2>NUL 14 | if errorlevel 9009 ( 15 | echo. 16 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 17 | echo.installed, then set the SPHINXBUILD environment variable to point 18 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 19 | echo.may add the Sphinx directory to PATH. 20 | echo. 21 | echo.If you don't have Sphinx installed, grab it from 22 | echo.https://www.sphinx-doc.org/ 23 | exit /b 1 24 | ) 25 | 26 | if "%1" == "" goto help 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /codalpy/utils/http.py: -------------------------------------------------------------------------------- 1 | from typing import Any, Literal 2 | 3 | import requests 4 | from requests.exceptions import HTTPError, RequestException, Timeout 5 | 6 | HEADERS = { 7 | "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36", 8 | } 9 | 10 | 11 | def get( 12 | url, 13 | params: dict[str, Any], 14 | rtype: Literal["josn", "text"], 15 | timeout: tuple[int, int] = (2, 10), 16 | ): 17 | 18 | try: 19 | r = requests.get(url=url, params=params, timeout=timeout, headers=HEADERS) 20 | match rtype: 21 | case "josn": 22 | return r.json() 23 | case "text": 24 | return r.text 25 | except HTTPError as e: 26 | print(f"HTTP error occurred: {e}") 27 | except Timeout as e: 28 | print(f"Timeout error occurred: {e}") 29 | except RequestException as e: 30 | print(f"n error error occurred: {e}") 31 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Yaghoub Ghaderi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /docs/_build/_static/webpack-macros.html: -------------------------------------------------------------------------------- 1 | 5 | 6 | {% macro head_pre_assets() %} 7 | 8 | 9 | 10 | {% endmacro %} 11 | 12 | {% macro head_js_preload() %} 13 | 14 | 15 | 16 | 17 | 18 | {% endmacro %} 19 | 20 | {% macro body_post() %} 21 | 22 | 23 | 24 | {% endmacro %} 25 | -------------------------------------------------------------------------------- /codalpy/utils/utils.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | import jdatetime as jdt 4 | 5 | 6 | def norm_char(w: str) -> str: 7 | dict_ = { 8 | "ي": "ی", 9 | "ك": "ک", 10 | "\u200c": " ", 11 | "۰": "0", 12 | "۱": "1", 13 | "۲": "2", 14 | "۳": "3", 15 | "۴": "4", 16 | "۵": "5", 17 | "۶": "6", 18 | "۷": "7", 19 | "۸": "8", 20 | "۹": "9", 21 | "/": "-", 22 | } 23 | return w.translate(str.maketrans(dict_)) 24 | 25 | 26 | def normalize_fs_item(w: str) -> str: 27 | dict_ = { 28 | " ": "", 29 | "–": "", 30 | "(": "", 31 | ")": "", 32 | "،": "", 33 | "ي": "ی", 34 | "ى": "ی", 35 | "آ": "ا", 36 | "\u200f": "", 37 | "\u200c": "", 38 | } 39 | return w.translate(str.maketrans(dict_)) 40 | 41 | 42 | def translate(item: str, dict_: dict) -> str: 43 | for k, v in dict_.items(): 44 | if item and normalize_fs_item(k) == normalize_fs_item(item): 45 | return v 46 | return item 47 | 48 | 49 | def fiscal_month(fiscal_year_ending_date: str, period_ending_date: str) -> int: 50 | fm = [3, 6, 9, 12] 51 | days = ( 52 | jdt.date.fromisoformat(fiscal_year_ending_date.replace("/", "-")).togregorian() 53 | - jdt.date.fromisoformat(period_ending_date.replace("/", "-")).togregorian() 54 | ).days 55 | return min(fm, key=lambda x: abs(x - (365 - days) / 30)) 56 | 57 | 58 | def pascal_to_snake_case(s: str) -> str: 59 | # Find all uppercase letters and insert an underscore before them, except at the start 60 | s = re.sub(r"(?>> " 32 | 33 | autoapi_options = [ 34 | "members", 35 | "undoc-members", 36 | "show-inheritance", 37 | "show-module-summary", 38 | "special-members", 39 | "imported-members", 40 | ] 41 | 42 | mathjax3_config = {"chtml": {"displayAlign": "left"}} 43 | 44 | templates_path = ["_templates"] 45 | exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] 46 | 47 | autoapi_type = "python" 48 | autoapi_dirs = ["../codalpy"] 49 | autoapi_ignore = ["*utils*"] 50 | 51 | autoclass_content = "both" 52 | 53 | source_suffix = ".rst" 54 | add_module_names = False 55 | 56 | 57 | # -- Options for HTML output ------------------------------------------------- 58 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output 59 | 60 | html_theme = "pydata_sphinx_theme" 61 | html_static_path = ["_static"] 62 | -------------------------------------------------------------------------------- /codalpy/utils/cols.py: -------------------------------------------------------------------------------- 1 | select = { 2 | "income_statement": { 3 | "production": [ 4 | "sales", 5 | "cost_of_sales", 6 | "gross_profit", 7 | "operating_expenses", 8 | "exceptional_cost", 9 | "other_operating_income", 10 | "other_operating_expense", 11 | "operating_income", 12 | "interest_expense", 13 | "other_income", 14 | "pretax_income", 15 | "taxes", 16 | "net_income_from_continuing_operations", 17 | "discontinued_operations", 18 | "net_income", 19 | "earnings_per_share", 20 | "shares_outstanding", 21 | ] 22 | }, 23 | "balance_sheet": { 24 | "production": [ 25 | "property_plant_and_equipment", 26 | "investment_property", 27 | "goodwill", 28 | "long_term_investments", 29 | "long_term_receivable", 30 | "deferred_tax_assets", 31 | "other_long_term_assets", 32 | "total_non_current_assets", 33 | "prepayments", 34 | "inventories", 35 | "trade_and_other_receivables", 36 | "short_term_investments", 37 | "cash", 38 | "assets_held_for_sale", 39 | "total_current_assets", 40 | "total_assets", 41 | "share_capital", 42 | "receives_for_capital_advance", 43 | "capital_surplus", 44 | "treasury_shares_surplus", 45 | "legal_reserve", 46 | "other_reserves", 47 | "revaluation_reserve", 48 | "translation_reserve", 49 | "retained_earnings", 50 | "treasury_shares", 51 | "total_equity", 52 | "long_term_payables", 53 | "long_term_debt", 54 | "deferred_tax_liabilities", 55 | "pension_and_other_employee_obligations", 56 | "total_non_current_liabilities", 57 | "trade_and_other_payables", 58 | "current_tax_liabilities", 59 | "dividends_payable", 60 | "short_term_debt", 61 | "provisions", 62 | "deferred_revenue", 63 | "liabilities_held_for_sale", 64 | "total_current_liabilities", 65 | "total_liabilities", 66 | "total_equity_and_liabilities", 67 | ] 68 | }, 69 | } 70 | -------------------------------------------------------------------------------- /docs/_build/_static/copybutton.css: -------------------------------------------------------------------------------- 1 | /* Copy buttons */ 2 | button.copybtn { 3 | position: absolute; 4 | display: flex; 5 | top: .3em; 6 | right: .3em; 7 | width: 1.7em; 8 | height: 1.7em; 9 | opacity: 0; 10 | transition: opacity 0.3s, border .3s, background-color .3s; 11 | user-select: none; 12 | padding: 0; 13 | border: none; 14 | outline: none; 15 | border-radius: 0.4em; 16 | /* The colors that GitHub uses */ 17 | border: #1b1f2426 1px solid; 18 | background-color: #f6f8fa; 19 | color: #57606a; 20 | } 21 | 22 | button.copybtn.success { 23 | border-color: #22863a; 24 | color: #22863a; 25 | } 26 | 27 | button.copybtn svg { 28 | stroke: currentColor; 29 | width: 1.5em; 30 | height: 1.5em; 31 | padding: 0.1em; 32 | } 33 | 34 | div.highlight { 35 | position: relative; 36 | } 37 | 38 | /* Show the copybutton */ 39 | .highlight:hover button.copybtn, button.copybtn.success { 40 | opacity: 1; 41 | } 42 | 43 | .highlight button.copybtn:hover { 44 | background-color: rgb(235, 235, 235); 45 | } 46 | 47 | .highlight button.copybtn:active { 48 | background-color: rgb(187, 187, 187); 49 | } 50 | 51 | /** 52 | * A minimal CSS-only tooltip copied from: 53 | * https://codepen.io/mildrenben/pen/rVBrpK 54 | * 55 | * To use, write HTML like the following: 56 | * 57 | *

Short

58 | */ 59 | .o-tooltip--left { 60 | position: relative; 61 | } 62 | 63 | .o-tooltip--left:after { 64 | opacity: 0; 65 | visibility: hidden; 66 | position: absolute; 67 | content: attr(data-tooltip); 68 | padding: .2em; 69 | font-size: .8em; 70 | left: -.2em; 71 | background: grey; 72 | color: white; 73 | white-space: nowrap; 74 | z-index: 2; 75 | border-radius: 2px; 76 | transform: translateX(-102%) translateY(0); 77 | transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); 78 | } 79 | 80 | .o-tooltip--left:hover:after { 81 | display: block; 82 | opacity: 1; 83 | visibility: visible; 84 | transform: translateX(-100%) translateY(0); 85 | transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); 86 | transition-delay: .5s; 87 | } 88 | 89 | /* By default the copy button shouldn't show up when printing a page */ 90 | @media print { 91 | button.copybtn { 92 | display: none; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /codalpy/utils/query.py: -------------------------------------------------------------------------------- 1 | import re 2 | from dataclasses import dataclass 3 | from enum import Enum 4 | from typing import Annotated, Literal 5 | 6 | import jdatetime as jdt 7 | from pydantic import BaseModel, BeforeValidator, ConfigDict, alias_generators 8 | 9 | 10 | @dataclass 11 | class Consts: 12 | base_url: str = "https://www.codal.ir" 13 | base_search_url: str = "https://search.codal.ir" 14 | api_endpoint: str = "/api/search/v2/q" 15 | 16 | @property 17 | def search_url(self): 18 | return f"{self.base_search_url}{self.api_endpoint}" 19 | 20 | 21 | def validate_jdate(jdate: str): 22 | """Validate Jalali date format. 23 | returns: str yyyy/mm/dd 24 | """ 25 | pattern = r"^(\d{4})[-/](\d{2})[-/](\d{2})$" 26 | match = re.match(pattern, jdate) 27 | if not match: 28 | raise ValueError("Invalid date format. Use YYYY-MM-DD or YYYY/MM/DD") 29 | year, month, day = map(int, match.groups()) 30 | try: 31 | return jdt.date(year, month, day).strftime("%Y/%m/%d") 32 | except ValueError: 33 | raise ValueError("Invalid Jalali date") 34 | 35 | 36 | JDate = Annotated[str, BeforeValidator(validate_jdate)] 37 | 38 | 39 | class QueryCategory(Enum): 40 | ALL = -1 41 | ANNUAL_FINANCIAL_STATEMETNS = 1 # اطلاعات و صورت مالی سالانه 42 | MONTHLY_ACTIVITY = 3 # گزارش عملکرد ماهانه 43 | 44 | 45 | class QueryLetterType(Enum): 46 | ALL = -1 47 | INTERIM_FINANCIAL_STATEMENTS = 6 # صورت‌های مالی میان‌دوره‌ای 48 | PORTFOLIO_POSITION = 8 # صورت وضعیت پورتفوی 49 | MONTHLY_ACTIVITY = 58 # گزارش عملکرد ماهانه 50 | 51 | 52 | class QueryParam(BaseModel): 53 | model_config = ConfigDict( 54 | alias_generator=alias_generators.to_pascal, populate_by_name=True 55 | ) 56 | 57 | symbol: str 58 | category: QueryCategory = QueryCategory.ALL # گروه اطلاعیه 59 | publisher_type: Literal[1] = 1 # نوع شرکت --> ناشران 60 | letter_type: QueryLetterType = QueryLetterType.ALL 61 | length: Literal[-1, 3, 6, 9, 12] = -1 # طول دوره 62 | audited: bool = True # حسابرسی شده 63 | not_audited: bool = True # حسابرسی نشده 64 | mains: bool = True # فقط شرکت اصلی ok 65 | childs: bool = False # فقط زیر-مجموعه‌ها ok 66 | consolidatable: bool = True # اصلی ok 67 | not_consolidatable: bool = True # تلفیقی ok 68 | auditor_ref: Literal[-1] = -1 69 | company_state: Literal[0, 1, 2] = 0 70 | company_type: Literal[-1, 1, 3] = -1 71 | page_number: int = 1 72 | tracing_no: Literal[-1] = -1 # ok 73 | publisher: bool = False # ok 74 | is_not_audited: bool = False 75 | from_date: JDate = "1396/01/01" 76 | to_date: JDate = "1405/01/01" 77 | -------------------------------------------------------------------------------- /codalpy/utils/fund.py: -------------------------------------------------------------------------------- 1 | from typing import cast 2 | 3 | import polars as pl 4 | from bs4 import BeautifulSoup 5 | from bs4.element import Tag 6 | 7 | 8 | def clean_raw_portfolio_df(df: pl.DataFrame) -> pl.DataFrame: 9 | values_idx = 0 10 | for row in df.rows(): 11 | isnumeric_ = sum([str(i).isnumeric() for i in row]) 12 | values_idx += 1 13 | if isnumeric_ > 4: 14 | break 15 | cols = [ 16 | "name", 17 | "volume_beg", 18 | "total_cost_beg", 19 | "net_proceeds_beg", 20 | "volume_pop", 21 | "total_cost_pop", 22 | "volume_sop", 23 | "sale_amount_sop", 24 | "volume_end", 25 | "price_end", 26 | "total_cost_end", 27 | "net_proceeds_end", 28 | "pct_of_total_assets_end", 29 | ] 30 | cols.reverse() 31 | data = {} 32 | idx = 0 33 | 34 | def is_number(s): 35 | try: 36 | float(s) 37 | return True 38 | except ValueError: 39 | return False 40 | 41 | for row in df[values_idx:].transpose().rows(): 42 | if cols: 43 | if idx == 0: 44 | is_numeric = sum([is_number(str(i)) for i in row]) 45 | if is_numeric < 3: 46 | data[cols.pop()] = row 47 | idx += 1 48 | else: 49 | is_numeric = sum([is_number(str(i)) for i in row]) 50 | if is_numeric > len(row) / 2: 51 | data[cols.pop()] = row 52 | idx += 1 53 | df = pl.DataFrame(data) 54 | df = ( 55 | df.drop_nulls() 56 | .filter(pl.col("name").str.len_chars() > 0) 57 | .with_columns( 58 | [pl.col(i).cast(pl.Float64).cast(pl.Int64) for i in df.columns[1:-1]] 59 | ) 60 | .with_columns( 61 | pct_of_total_assets_end=pl.col("pct_of_total_assets_end").cast(pl.Float64), 62 | ) 63 | ) 64 | return df 65 | 66 | 67 | def find_download_endpoint(html: str) -> list[dict[str, str]]: 68 | soup = BeautifulSoup(html, "html.parser") 69 | table = soup.find("table", {"id": "dgAttachmentList"}) 70 | data = [] 71 | if isinstance(table, Tag): 72 | rows = table.find_all("tr")[1:] 73 | for row in rows: 74 | if isinstance(row, Tag): 75 | onclick = cast(str, row.get("onclick") or "") 76 | link = None 77 | if "window.open" in onclick: 78 | link = onclick.split("'")[1] # متن داخل window.open('...') 79 | tds = row.find_all("td") 80 | description = tds[1].get_text(strip=True) if len(tds) > 1 else "" 81 | date_added = tds[2].get_text(strip=True) if len(tds) > 2 else "" 82 | 83 | data.append( 84 | {"link": link, "description": description, "date_added": date_added} 85 | ) 86 | return data 87 | -------------------------------------------------------------------------------- /docs/_build/_static/copybutton_funcs.js: -------------------------------------------------------------------------------- 1 | function escapeRegExp(string) { 2 | return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string 3 | } 4 | 5 | /** 6 | * Removes excluded text from a Node. 7 | * 8 | * @param {Node} target Node to filter. 9 | * @param {string} exclude CSS selector of nodes to exclude. 10 | * @returns {DOMString} Text from `target` with text removed. 11 | */ 12 | export function filterText(target, exclude) { 13 | const clone = target.cloneNode(true); // clone as to not modify the live DOM 14 | if (exclude) { 15 | // remove excluded nodes 16 | clone.querySelectorAll(exclude).forEach(node => node.remove()); 17 | } 18 | return clone.innerText; 19 | } 20 | 21 | // Callback when a copy button is clicked. Will be passed the node that was clicked 22 | // should then grab the text and replace pieces of text that shouldn't be used in output 23 | export function formatCopyText(textContent, copybuttonPromptText, isRegexp = false, onlyCopyPromptLines = true, removePrompts = true, copyEmptyLines = true, lineContinuationChar = "", hereDocDelim = "") { 24 | var regexp; 25 | var match; 26 | 27 | // Do we check for line continuation characters and "HERE-documents"? 28 | var useLineCont = !!lineContinuationChar 29 | var useHereDoc = !!hereDocDelim 30 | 31 | // create regexp to capture prompt and remaining line 32 | if (isRegexp) { 33 | regexp = new RegExp('^(' + copybuttonPromptText + ')(.*)') 34 | } else { 35 | regexp = new RegExp('^(' + escapeRegExp(copybuttonPromptText) + ')(.*)') 36 | } 37 | 38 | const outputLines = []; 39 | var promptFound = false; 40 | var gotLineCont = false; 41 | var gotHereDoc = false; 42 | const lineGotPrompt = []; 43 | for (const line of textContent.split('\n')) { 44 | match = line.match(regexp) 45 | if (match || gotLineCont || gotHereDoc) { 46 | promptFound = regexp.test(line) 47 | lineGotPrompt.push(promptFound) 48 | if (removePrompts && promptFound) { 49 | outputLines.push(match[2]) 50 | } else { 51 | outputLines.push(line) 52 | } 53 | gotLineCont = line.endsWith(lineContinuationChar) & useLineCont 54 | if (line.includes(hereDocDelim) & useHereDoc) 55 | gotHereDoc = !gotHereDoc 56 | } else if (!onlyCopyPromptLines) { 57 | outputLines.push(line) 58 | } else if (copyEmptyLines && line.trim() === '') { 59 | outputLines.push(line) 60 | } 61 | } 62 | 63 | // If no lines with the prompt were found then just use original lines 64 | if (lineGotPrompt.some(v => v === true)) { 65 | textContent = outputLines.join('\n'); 66 | } 67 | 68 | // Remove a trailing newline to avoid auto-running when pasting 69 | if (textContent.endsWith("\n")) { 70 | textContent = textContent.slice(0, -1) 71 | } 72 | return textContent 73 | } 74 | -------------------------------------------------------------------------------- /codalpy/utils/gen_df.py: -------------------------------------------------------------------------------- 1 | from typing import Literal 2 | 3 | import polars as pl 4 | 5 | from codalpy.utils import cols, dicts 6 | from codalpy.utils.issuer import IssuerCategory 7 | from codalpy.models import Cell, FinancialStatement, Letter 8 | from codalpy.utils.utils import ( 9 | fiscal_month, 10 | normalize_fs_item, 11 | pascal_to_snake_case, 12 | translate, 13 | ) 14 | 15 | 16 | def _cells( 17 | item: FinancialStatement, fs: Literal["BalanceSheet", "IncomeStatement"] 18 | ) -> list[Cell] | None: 19 | if item.sheets[0].tables[0].alias_name == fs: 20 | r = item.sheets[0].tables[0].cells 21 | if r: 22 | return r 23 | if item.sheets[0].tables[1].alias_name == fs: 24 | r = item.sheets[0].tables[1].cells 25 | if r: 26 | return r 27 | 28 | 29 | def cells_to_df(cells: list[Cell]) -> pl.DataFrame: 30 | cells_ = [(i.column_sequence, i.row_sequence, i.value) for i in cells] 31 | df = pl.from_records(cells_, schema=["col", "row", "value"], orient="row") 32 | df = df.pivot(values="value", on="col", index="row") 33 | df_filter = df.filter(pl.col("1") == "شرح") 34 | index = [] 35 | df_ = pl.DataFrame() 36 | for i, v in enumerate(df_filter.row(0)): 37 | if normalize_fs_item(str(v)) == "شرح": 38 | index.append(i) 39 | for i in index: 40 | selected = df.select([str(i), str(i + 1)]) 41 | selected.columns = ["item", "value"] 42 | df_ = pl.concat([df_, selected]) 43 | return df_ 44 | 45 | 46 | def clean_df( 47 | records: list[tuple[Letter, FinancialStatement]], 48 | category: IssuerCategory, 49 | fs: Literal["BalanceSheet", "IncomeStatement"], 50 | ) -> pl.DataFrame | None: 51 | snake_fs = pascal_to_snake_case(fs) 52 | df_concat = pl.DataFrame() 53 | dicts_key = "" 54 | match category: 55 | case IssuerCategory.MANUFACTURING: 56 | dicts_key = "manufacturing" 57 | 58 | for letter, data in records: 59 | cells = _cells(data, fs) 60 | if cells is not None: 61 | df = cells_to_df(cells) 62 | df = df.filter(pl.col("value") != "") 63 | df = df.with_columns( 64 | pl.struct(["item"]).map_elements( 65 | lambda x: translate(x["item"], dicts.dicts[snake_fs][dicts_key]), 66 | return_dtype=pl.String, 67 | ) 68 | ) 69 | df = df.filter( 70 | pl.col("item").is_in(dicts.dicts[snake_fs][dicts_key].values()) 71 | ).with_columns([pl.col("value").cast(pl.Int64), pl.lit(0).alias("index")]) 72 | df = df.pivot( 73 | values="value", 74 | on="item", 75 | index="index", 76 | aggregate_function="sum", 77 | ) 78 | miss_cols = set(cols.select[snake_fs][dicts_key]) - set(df.columns) 79 | if miss_cols: 80 | df = df.with_columns( 81 | [pl.lit(0).cast(pl.Int64).alias(i) for i in miss_cols] 82 | ) 83 | df = df.select(cols.select[snake_fs][dicts_key]) 84 | df = df.with_columns( 85 | [ 86 | pl.lit(data.is_audited).alias("is_audited"), 87 | pl.lit(data.period_end_to_date).alias("period_ending_date"), 88 | pl.lit(data.year_end_to_date).alias("fiscal_year_ending_date"), 89 | pl.lit( 90 | fiscal_month(data.year_end_to_date, data.period_end_to_date) 91 | ).alias("fiscal_month"), 92 | pl.lit(letter.publish_date_time).alias("publish_date_time"), 93 | pl.lit(False).alias("consolidated"), 94 | pl.lit(letter.symbol).alias("symbol"), 95 | pl.lit(letter.title).alias("title"), 96 | pl.lit(letter.url).alias("url"), 97 | pl.lit(letter.attachment_url).alias("attachment_url"), 98 | pl.lit(letter.pdf_url).alias("pdf_url"), 99 | pl.lit(letter.excel_url).alias("excel_url"), 100 | ] 101 | ) 102 | df_concat = pl.concat([df_concat, df]) 103 | 104 | return df_concat 105 | -------------------------------------------------------------------------------- /codalpy/models.py: -------------------------------------------------------------------------------- 1 | from typing import ClassVar, Optional 2 | 3 | from pydantic import BaseModel, ConfigDict, Field, alias_generators, field_validator 4 | from typing_extensions import Literal 5 | 6 | from codalpy.utils.utils import norm_char 7 | 8 | 9 | class Letter(BaseModel): 10 | model_config = ConfigDict( 11 | alias_generator=alias_generators.to_pascal, populate_by_name=True 12 | ) 13 | 14 | base_url: ClassVar[str] 15 | 16 | tracing_no: int 17 | symbol: str 18 | company_name: str 19 | title: str 20 | letter_code: str 21 | sent_date_time: str 22 | publish_date_time: str 23 | has_html: bool 24 | is_estimate: bool 25 | has_excel: bool 26 | has_pdf: bool 27 | has_xbrl: bool 28 | has_attachment: bool 29 | url: str 30 | attachment_url: str 31 | pdf_url: str 32 | excel_url: str 33 | 34 | @field_validator( 35 | "symbol", 36 | "company_name", 37 | "letter_code", 38 | "title", 39 | "sent_date_time", 40 | "publish_date_time", 41 | mode="after", 42 | ) 43 | def serialize_norm_char(cls, v: str): 44 | return norm_char(v) 45 | 46 | @field_validator("url", "attachment_url", "pdf_url", mode="after") 47 | def serialize_url(cls, v: str): 48 | if v: 49 | if v[0] != "/": 50 | v = f"/{v}" 51 | return f"{cls.base_url}{v}" 52 | 53 | 54 | class Cell(BaseModel): 55 | model_config = ConfigDict( 56 | alias_generator=alias_generators.to_camel, populate_by_name=True 57 | ) 58 | 59 | meta_table_id: int 60 | meta_table_code: int 61 | address: str 62 | formula: str 63 | validations: str 64 | financial_concept: Optional[str] 65 | cell_group_name: str 66 | category: int 67 | col_span: int 68 | column_code: int 69 | column_sequence: int 70 | decimal_place: int 71 | row_code: int 72 | row_sequence: int 73 | row_span: int 74 | row_type_name: str 75 | value: str 76 | value_type_name: str 77 | data_type_name: Optional[str] 78 | period_end_to_date: str 79 | year_end_to_date: str 80 | is_audited: bool 81 | 82 | 83 | class Table(BaseModel): 84 | model_config = ConfigDict( 85 | alias_generator=alias_generators.to_camel, populate_by_name=True 86 | ) 87 | meta_table_id: int 88 | title_fa: Optional[str] = Field(alias="title_Fa") 89 | title_en: Optional[str] = Field(alias="title_En") 90 | sequence: int 91 | sheet_code: int 92 | code: int 93 | description: Optional[str] 94 | alias_name: Optional[str] 95 | version_no: str 96 | cells: list[Cell] 97 | 98 | 99 | class Sheet(BaseModel): 100 | model_config = ConfigDict( 101 | alias_generator=alias_generators.to_camel, populate_by_name=True 102 | ) 103 | code: int 104 | title_fa: str = Field(alias="title_Fa") 105 | title_en: str = Field(alias="title_En") 106 | sequence: int 107 | is_dynamic: bool 108 | tables: list[Table] 109 | 110 | 111 | class FinancialStatement(BaseModel): 112 | model_config = ConfigDict( 113 | alias_generator=alias_generators.to_camel, populate_by_name=True 114 | ) 115 | 116 | is_audited: bool 117 | period: int 118 | period_end_to_date: str 119 | period_extra_day: int 120 | register_date_time: str 121 | sent_date_time: str | None 122 | sheets: list[Sheet] 123 | type: int 124 | year_end_to_date: str 125 | 126 | 127 | class GetFinancialStatement(BaseModel): 128 | records: list[tuple[Letter, FinancialStatement]] 129 | get_error: list[Letter] 130 | match_error: list[tuple[Letter, str]] 131 | validation_error: list[tuple[Letter, str]] 132 | 133 | 134 | class DataSource(BaseModel): 135 | model_config = ConfigDict( 136 | alias_generator=alias_generators.to_camel, populate_by_name=True 137 | ) 138 | title_fa: str = Field(alias="title_Fa") 139 | title_en: str = Field(alias="title_En") 140 | subject: Optional[str] 141 | dsc: Optional[str] 142 | type: int 143 | period: int 144 | period_end_to_date: str 145 | year_end_to_date: str 146 | period_extra_day: int 147 | isConsolidated: bool 148 | tracing_no: int 149 | kind: int 150 | is_audited: bool 151 | audit_state: int 152 | register_date_time: str 153 | sent_date_time: str 154 | publish_date_time: str 155 | state: int 156 | is_for_auditing: bool 157 | sheets: list[Sheet] 158 | 159 | 160 | class GetDataSourceError(BaseModel): 161 | source: Literal["match", "validation"] 162 | message: str 163 | 164 | 165 | class DataSourceResult(BaseModel): 166 | status: Literal["success", "error"] 167 | letter: Letter 168 | data: Optional[DataSource] 169 | error: Optional[GetDataSourceError] 170 | -------------------------------------------------------------------------------- /docs/_build/_static/doctools.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Base JavaScript utilities for all Sphinx HTML documentation. 3 | */ 4 | "use strict"; 5 | 6 | const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([ 7 | "TEXTAREA", 8 | "INPUT", 9 | "SELECT", 10 | "BUTTON", 11 | ]); 12 | 13 | const _ready = (callback) => { 14 | if (document.readyState !== "loading") { 15 | callback(); 16 | } else { 17 | document.addEventListener("DOMContentLoaded", callback); 18 | } 19 | }; 20 | 21 | /** 22 | * Small JavaScript module for the documentation. 23 | */ 24 | const Documentation = { 25 | init: () => { 26 | Documentation.initDomainIndexTable(); 27 | Documentation.initOnKeyListeners(); 28 | }, 29 | 30 | /** 31 | * i18n support 32 | */ 33 | TRANSLATIONS: {}, 34 | PLURAL_EXPR: (n) => (n === 1 ? 0 : 1), 35 | LOCALE: "unknown", 36 | 37 | // gettext and ngettext don't access this so that the functions 38 | // can safely bound to a different name (_ = Documentation.gettext) 39 | gettext: (string) => { 40 | const translated = Documentation.TRANSLATIONS[string]; 41 | switch (typeof translated) { 42 | case "undefined": 43 | return string; // no translation 44 | case "string": 45 | return translated; // translation exists 46 | default: 47 | return translated[0]; // (singular, plural) translation tuple exists 48 | } 49 | }, 50 | 51 | ngettext: (singular, plural, n) => { 52 | const translated = Documentation.TRANSLATIONS[singular]; 53 | if (typeof translated !== "undefined") 54 | return translated[Documentation.PLURAL_EXPR(n)]; 55 | return n === 1 ? singular : plural; 56 | }, 57 | 58 | addTranslations: (catalog) => { 59 | Object.assign(Documentation.TRANSLATIONS, catalog.messages); 60 | Documentation.PLURAL_EXPR = new Function( 61 | "n", 62 | `return (${catalog.plural_expr})` 63 | ); 64 | Documentation.LOCALE = catalog.locale; 65 | }, 66 | 67 | /** 68 | * helper function to focus on search bar 69 | */ 70 | focusSearchBar: () => { 71 | document.querySelectorAll("input[name=q]")[0]?.focus(); 72 | }, 73 | 74 | /** 75 | * Initialise the domain index toggle buttons 76 | */ 77 | initDomainIndexTable: () => { 78 | const toggler = (el) => { 79 | const idNumber = el.id.substr(7); 80 | const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`); 81 | if (el.src.substr(-9) === "minus.png") { 82 | el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`; 83 | toggledRows.forEach((el) => (el.style.display = "none")); 84 | } else { 85 | el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`; 86 | toggledRows.forEach((el) => (el.style.display = "")); 87 | } 88 | }; 89 | 90 | const togglerElements = document.querySelectorAll("img.toggler"); 91 | togglerElements.forEach((el) => 92 | el.addEventListener("click", (event) => toggler(event.currentTarget)) 93 | ); 94 | togglerElements.forEach((el) => (el.style.display = "")); 95 | if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); 96 | }, 97 | 98 | initOnKeyListeners: () => { 99 | // only install a listener if it is really needed 100 | if ( 101 | !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && 102 | !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS 103 | ) 104 | return; 105 | 106 | document.addEventListener("keydown", (event) => { 107 | // bail for input elements 108 | if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; 109 | // bail with special keys 110 | if (event.altKey || event.ctrlKey || event.metaKey) return; 111 | 112 | if (!event.shiftKey) { 113 | switch (event.key) { 114 | case "ArrowLeft": 115 | if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; 116 | 117 | const prevLink = document.querySelector('link[rel="prev"]'); 118 | if (prevLink && prevLink.href) { 119 | window.location.href = prevLink.href; 120 | event.preventDefault(); 121 | } 122 | break; 123 | case "ArrowRight": 124 | if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; 125 | 126 | const nextLink = document.querySelector('link[rel="next"]'); 127 | if (nextLink && nextLink.href) { 128 | window.location.href = nextLink.href; 129 | event.preventDefault(); 130 | } 131 | break; 132 | } 133 | } 134 | 135 | // some keyboard layouts may need Shift to get / 136 | switch (event.key) { 137 | case "/": 138 | if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; 139 | Documentation.focusSearchBar(); 140 | event.preventDefault(); 141 | } 142 | }); 143 | }, 144 | }; 145 | 146 | // quick alias for translations 147 | const _ = Documentation.gettext; 148 | 149 | _ready(Documentation.init); 150 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # metafid 2 | ## Codal 3 | 4 | ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/codalpy) 5 | ![PyPI - Version](https://img.shields.io/pypi/v/codalpy) 6 | ![PyPI - Downloads](https://img.shields.io/pypi/dm/codalpy?logoColor=blue&color=blue) 7 | ![GitHub](https://img.shields.io/github/license/yghaderi/codalpy) 8 | 9 |
10 | کدال برای گرفتن و پالایشِ داده از codal.ir در حالِ توسعه است. 11 |
12 | راهنمایِ بهره-گیران 13 |
14 | 15 | 16 | 17 | | حمایت از من | لینک | 18 | |-------------|--------------------------------------------------| 19 | | دارمت | [یه ☕🧸🍪 مهمونم کن](https://daramet.com/yghaderi) | 20 | | 21 | 22 | 23 | ## install 24 | ```bash 25 | python -m pip install codalpy 26 | ``` 27 | 28 | 29 | 30 | 31 | ## صورت‌هایِ مالی 32 | ### صورت عملکردِ مالی 33 | 34 | ```python 35 | from codalpy import Codal 36 | codal = Codal( 37 | issuer = "شپدیس", 38 | from_jdate = "1401/01/01", 39 | to_jdate = "1404/12/29" 40 | ) 41 | data = codal.income_statement() 42 | ``` 43 | 44 | ### صورت وضعیتِ مالی 45 | 46 | ```python 47 | from codalpy import Codal 48 | codal = Codal( 49 | issuer = "شپدیس", 50 | from_jdate = "1401/01/01", 51 | to_jdate = "1404/12/29" 52 | ) 53 | data = codal.balance_sheet() 54 | ``` 55 | 56 | 57 | ### فعالیتِ ماهانه 58 | 59 | ```python 60 | from codalpy import Codal 61 | codal = Codal( 62 | issuer = "شپدیس", 63 | from_jdate = "1404/01/01", 64 | to_jdate = "1404/12/29" 65 | ) 66 | data = codal.monthly_activity() 67 | ``` 68 | 69 | ### صورت وضعیت پورتفوی صندوق سرمایه گذاری 70 | ```python 71 | from codalpy import Codal 72 | codal = Codal(issuer = "اهرم", from_jdate= "1404-04-04", to_jdate="1404-06-06") 73 | codal.fund_monthly_portfolio() 74 | """ 75 | shape: (603, 18) 76 | ┌──────────────────────────────┬────────────┬────────────────┬──────────────────┬───┬────────┬─────────────────────────────────┬─────────────────────────────────┬─────────────────────────────────┐ 77 | │ name ┆ volume_beg ┆ total_cost_beg ┆ net_proceeds_beg ┆ … ┆ symbol ┆ title ┆ url ┆ attachment_url │ 78 | │ --- ┆ --- ┆ --- ┆ --- ┆ ┆ --- ┆ --- ┆ --- ┆ --- │ 79 | │ str ┆ i64 ┆ i64 ┆ i64 ┆ ┆ str ┆ str ┆ str ┆ str │ 80 | ╞══════════════════════════════╪════════════╪════════════════╪══════════════════╪═══╪════════╪═════════════════════════════════╪═════════════════════════════════╪═════════════════════════════════╡ 81 | │ آهن و فولاد غدیر ایرانیان ┆ 24500000 ┆ 140495106806 ┆ 123719463000 ┆ … ┆ اهرم ┆ صورت وضعیت پورتفوی صندوق سرمای… ┆ https://www.codal.ir/Reports/A… ┆ https://www.codal.ir/Reports/A… │ 82 | │ اقتصادی و خودکفایی آزادگان ┆ 58949663 ┆ 428681824109 ┆ 363313257531 ┆ … ┆ اهرم ┆ صورت وضعیت پورتفوی صندوق سرمای… ┆ https://www.codal.ir/Reports/A… ┆ https://www.codal.ir/Reports/A… │ 83 | │ البرزدارو ┆ 266248175 ┆ 853755414625 ┆ 982697425906 ┆ … ┆ اهرم ┆ صورت وضعیت پورتفوی صندوق سرمای… ┆ https://www.codal.ir/Reports/A… ┆ https://www.codal.ir/Reports/A… │ 84 | │ الحاوی ┆ 79400000 ┆ 175805992152 ┆ 102290130720 ┆ … ┆ اهرم ┆ صورت وضعیت پورتفوی صندوق سرمای… ┆ https://www.codal.ir/Reports/A… ┆ https://www.codal.ir/Reports/A… │ 85 | │ الکتریک‌ خودرو شرق‌ ┆ 117032944 ┆ 427355209792 ┆ 310735053213 ┆ … ┆ اهرم ┆ صورت وضعیت پورتفوی صندوق سرمای… ┆ https://www.codal.ir/Reports/A… ┆ https://www.codal.ir/Reports/A… │ 86 | │ … ┆ … ┆ … ┆ … ┆ … ┆ … ┆ … ┆ … ┆ … │ 87 | │ کشت و دامداری فکا ┆ 38000000 ┆ 42921313500 ┆ 137950282800 ┆ … ┆ اهرم ┆ صورت وضعیت پورتفوی صندوق سرمای… ┆ https://www.codal.ir/Reports/A… ┆ https://www.codal.ir/Reports/A… │ 88 | │ کویر تایر ┆ 84043466 ┆ 168768973101 ┆ 619056648665 ┆ … ┆ اهرم ┆ صورت وضعیت پورتفوی صندوق سرمای… ┆ https://www.codal.ir/Reports/A… ┆ https://www.codal.ir/Reports/A… │ 89 | │ ح . سرمایه گذاری‌البرز(هلدینگ‌ ┆ 0 ┆ 0 ┆ 0 ┆ … ┆ اهرم ┆ صورت وضعیت پورتفوی صندوق سرمای… ┆ https://www.codal.ir/Reports/A… ┆ https://www.codal.ir/Reports/A… │ 90 | │ سنگ آهن گهرزمین ┆ 0 ┆ 0 ┆ 0 ┆ … ┆ اهرم ┆ صورت وضعیت پورتفوی صندوق سرمای… ┆ https://www.codal.ir/Reports/A… ┆ https://www.codal.ir/Reports/A… │ 91 | │ ح . سنگ آهن گهرزمین ┆ 0 ┆ 0 ┆ 0 ┆ … ┆ اهرم ┆ صورت وضعیت پورتفوی صندوق سرمای… ┆ https://www.codal.ir/Reports/A… ┆ https://www.codal.ir/Reports/A… │ 92 | └──────────────────────────────┴────────────┴────────────────┴──────────────────┴───┴────────┴─────────────────────────────────┴─────────────────────────────────┴─────────────────────────────────┘ 93 | """ 94 | ``` 95 | -------------------------------------------------------------------------------- /codalpy/utils/dicts.py: -------------------------------------------------------------------------------- 1 | dicts = { 2 | "income_statement": { 3 | "manufacturing": { 4 | "درآمدهاي عملياتي": "sales", 5 | "بهاى تمام شده درآمدهاي عملياتي": "cost_of_sales", 6 | "سود(زيان) ناخالص": "gross_profit", 7 | "هزينه‏ هاى فروش، ادارى و عمومى": "operating_expenses", 8 | "هزينه کاهش ارزش دريافتني‏ ها (هزينه استثنايي)": "exceptional_cost", 9 | "ساير درآمدها": "other_operating_income", 10 | "سایر درآمدهای عملیاتی": "other_operating_income", 11 | "سایر هزینه ها": "other_operating_expense", 12 | "سایر هزینه‌های عملیاتی": "other_operating_expense", 13 | "سود(زيان) عملياتى": "operating_income", 14 | "هزينه‏ هاى مالى": "interest_expense", 15 | "ساير درآمدها و هزينه ‏هاى غيرعملياتى": "other_income", 16 | "سایر درآمدها و هزینه‌های غیرعملیاتی- درآمد سرمایه‌گذاری‌ها": "other_income", 17 | "سایر درآمدها و هزینه‌های غیرعملیاتی- اقلام متفرقه": "other_income", 18 | "سود(زيان) عمليات در حال تداوم قبل از ماليات": "pretax_income", 19 | "مالیات بر درآمد": "taxes", 20 | "سال جاري": "taxes", 21 | "سال‌هاي قبل": "taxes", 22 | "سود(زيان) خالص عمليات در حال تداوم": "net_income_from_continuing_operations", 23 | "سود (زيان) خالص عمليات متوقف شده": "discontinued_operations", 24 | "سود (زیان) عملیات متوقف ‌شده پس از اثر مالیاتی": "discontinued_operations", 25 | "سود(زيان) خالص": "net_income", 26 | "سود (زيان) خالص هر سهم – ريال": "earnings_per_share", 27 | "سرمایه": "shares_outstanding", 28 | } 29 | }, 30 | "balance_sheet": { 31 | "manufacturing": { 32 | "دارايي‌هاي ثابت مشهود": "property_plant_and_equipment", 33 | "سرمايه‌گذاري در املاک": "investment_property", 34 | "دارايي‌هاي نامشهود": "goodwill", 35 | "سرمايه‌گذاري‌هاي بلندمدت": "long_term_investments", 36 | "دريافتني‌هاي بلندمدت": "long_term_receivable", 37 | "دارايي ماليات انتقالي": "deferred_tax_assets", 38 | "ساير دارايي‌ها": "other_long_term_assets", 39 | "جمع دارايي‌هاي غيرجاري": "total_non_current_assets", 40 | "سفارشات و پيش‌پرداخت‌ها": "prepayments", 41 | "پیش پرداخت‌ها و سفارشات": "prepayments", 42 | "موجودي مواد و کالا": "inventories", 43 | "دريافتني‌هاي تجاري و ساير دريافتني‌ها": "trade_and_other_receivables", 44 | "دریافتنی‌‌های تجاری": "trade_and_other_receivables", 45 | "دریافتنی‌‌های غیرتجاری": "trade_and_other_receivables", 46 | "سرمايه‌گذاري‌هاي کوتاه‌مدت": "short_term_investments", 47 | "موجودي نقد": "cash", 48 | "دارايي‌هاي نگهداري شده براي فروش": "assets_held_for_sale", 49 | "جمع دارايي‌هاي جاري": "total_current_assets", 50 | "جمع دارايي‌ها": "total_assets", 51 | "سرمايه": "share_capital", 52 | "افزايش سرمايه در جريان": "receives_for_capital_advance", 53 | "افزایش (کاهش) سرمایه در جریان": "receives_for_capital_advance", 54 | "صرف سهام": "capital_surplus", 55 | "صرف (کسر) سهام": "capital_surplus", 56 | "صرف سهام خزانه": "treasury_shares_surplus", 57 | "اندوخته قانوني": "legal_reserve", 58 | "ساير اندوخته‌ها": "other_reserves", 59 | "مازاد تجديدارزيابي دارايي‌ها": "revaluation_reserve", 60 | "مازاد تجدید ارزیابی دارایی\u200cهای نگهداری شده برای فروش": "revaluation_reserve", 61 | "تفاوت تسعير ارز عمليات خارجي": "translation_reserve", 62 | "اندوخته تسعیر ارز دارایی\u200cها و بدهی\u200cهای شرکت\u200cهای دولتی": "translation_reserve", 63 | "تفاوت تسعیر ناشی از تبدیل به واحد پول گزارشگری": "translation_reserve", 64 | "سود(زيان) انباشته": "retained_earnings", 65 | "سهام خزانه": "treasury_shares", 66 | "جمع حقوق مالکانه": "total_equity", 67 | "جمع حقوق صاحبان سهام": "total_equity", 68 | "پرداختني‌هاي بلندمدت": "long_term_payables", 69 | "تسهيلات مالي بلندمدت": "long_term_debt", 70 | "بدهي ماليات انتقالي": "deferred_tax_liabilities", 71 | "ذخيره مزاياي پايان خدمت کارکنان": "pension_and_other_employee_obligations", 72 | "جمع بدهي‌هاي غيرجاري": "total_non_current_liabilities", 73 | "پرداختني‌هاي تجاري و ساير پرداختني‌ها": "trade_and_other_payables", 74 | "پرداختنی‌های تجاری": "trade_and_other_payables", 75 | "پرداختنی‌های غیرتجاری": "trade_and_other_payables", 76 | "ماليات پرداختني": "current_tax_liabilities", 77 | "سود سهام پرداختني": "dividends_payable", 78 | "تسهيلات مالي": "short_term_debt", 79 | "ذخاير": "provisions", 80 | "پيش‌دريافت‌ها": "deferred_revenue", 81 | "پیش‌دریافت‌های جاری": "deferred_revenue", 82 | "پیش‌دریافت‌های غیرجاری": "deferred_revenue", 83 | "بدهي‌هاي ‌مرتبط ‌با دارايي‌هاي نگهداري‌‌شده براي ‌فروش": "liabilities_held_for_sale", 84 | "جمع بدهي‌هاي جاري": "total_current_liabilities", 85 | "جمع بدهي‌ها": "total_liabilities", 86 | "جمع حقوق مالکانه و بدهي‌ها": "total_equity_and_liabilities", 87 | "جمع بدهی\u200cها و حقوق صاحبان سهام": "total_equity_and_liabilities", 88 | } 89 | }, 90 | } 91 | -------------------------------------------------------------------------------- /docs/_build/_static/language_data.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This script contains the language-specific data used by searchtools.js, 3 | * namely the list of stopwords, stemmer, scorer and splitter. 4 | */ 5 | 6 | var stopwords = ["a", "and", "are", "as", "at", "be", "but", "by", "for", "if", "in", "into", "is", "it", "near", "no", "not", "of", "on", "or", "such", "that", "the", "their", "then", "there", "these", "they", "this", "to", "was", "will", "with"]; 7 | 8 | 9 | /* Non-minified version is copied as a separate JS file, if available */ 10 | 11 | /** 12 | * Porter Stemmer 13 | */ 14 | var Stemmer = function() { 15 | 16 | var step2list = { 17 | ational: 'ate', 18 | tional: 'tion', 19 | enci: 'ence', 20 | anci: 'ance', 21 | izer: 'ize', 22 | bli: 'ble', 23 | alli: 'al', 24 | entli: 'ent', 25 | eli: 'e', 26 | ousli: 'ous', 27 | ization: 'ize', 28 | ation: 'ate', 29 | ator: 'ate', 30 | alism: 'al', 31 | iveness: 'ive', 32 | fulness: 'ful', 33 | ousness: 'ous', 34 | aliti: 'al', 35 | iviti: 'ive', 36 | biliti: 'ble', 37 | logi: 'log' 38 | }; 39 | 40 | var step3list = { 41 | icate: 'ic', 42 | ative: '', 43 | alize: 'al', 44 | iciti: 'ic', 45 | ical: 'ic', 46 | ful: '', 47 | ness: '' 48 | }; 49 | 50 | var c = "[^aeiou]"; // consonant 51 | var v = "[aeiouy]"; // vowel 52 | var C = c + "[^aeiouy]*"; // consonant sequence 53 | var V = v + "[aeiou]*"; // vowel sequence 54 | 55 | var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0 56 | var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 57 | var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 58 | var s_v = "^(" + C + ")?" + v; // vowel in stem 59 | 60 | this.stemWord = function (w) { 61 | var stem; 62 | var suffix; 63 | var firstch; 64 | var origword = w; 65 | 66 | if (w.length < 3) 67 | return w; 68 | 69 | var re; 70 | var re2; 71 | var re3; 72 | var re4; 73 | 74 | firstch = w.substr(0,1); 75 | if (firstch == "y") 76 | w = firstch.toUpperCase() + w.substr(1); 77 | 78 | // Step 1a 79 | re = /^(.+?)(ss|i)es$/; 80 | re2 = /^(.+?)([^s])s$/; 81 | 82 | if (re.test(w)) 83 | w = w.replace(re,"$1$2"); 84 | else if (re2.test(w)) 85 | w = w.replace(re2,"$1$2"); 86 | 87 | // Step 1b 88 | re = /^(.+?)eed$/; 89 | re2 = /^(.+?)(ed|ing)$/; 90 | if (re.test(w)) { 91 | var fp = re.exec(w); 92 | re = new RegExp(mgr0); 93 | if (re.test(fp[1])) { 94 | re = /.$/; 95 | w = w.replace(re,""); 96 | } 97 | } 98 | else if (re2.test(w)) { 99 | var fp = re2.exec(w); 100 | stem = fp[1]; 101 | re2 = new RegExp(s_v); 102 | if (re2.test(stem)) { 103 | w = stem; 104 | re2 = /(at|bl|iz)$/; 105 | re3 = new RegExp("([^aeiouylsz])\\1$"); 106 | re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); 107 | if (re2.test(w)) 108 | w = w + "e"; 109 | else if (re3.test(w)) { 110 | re = /.$/; 111 | w = w.replace(re,""); 112 | } 113 | else if (re4.test(w)) 114 | w = w + "e"; 115 | } 116 | } 117 | 118 | // Step 1c 119 | re = /^(.+?)y$/; 120 | if (re.test(w)) { 121 | var fp = re.exec(w); 122 | stem = fp[1]; 123 | re = new RegExp(s_v); 124 | if (re.test(stem)) 125 | w = stem + "i"; 126 | } 127 | 128 | // Step 2 129 | re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; 130 | if (re.test(w)) { 131 | var fp = re.exec(w); 132 | stem = fp[1]; 133 | suffix = fp[2]; 134 | re = new RegExp(mgr0); 135 | if (re.test(stem)) 136 | w = stem + step2list[suffix]; 137 | } 138 | 139 | // Step 3 140 | re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; 141 | if (re.test(w)) { 142 | var fp = re.exec(w); 143 | stem = fp[1]; 144 | suffix = fp[2]; 145 | re = new RegExp(mgr0); 146 | if (re.test(stem)) 147 | w = stem + step3list[suffix]; 148 | } 149 | 150 | // Step 4 151 | re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; 152 | re2 = /^(.+?)(s|t)(ion)$/; 153 | if (re.test(w)) { 154 | var fp = re.exec(w); 155 | stem = fp[1]; 156 | re = new RegExp(mgr1); 157 | if (re.test(stem)) 158 | w = stem; 159 | } 160 | else if (re2.test(w)) { 161 | var fp = re2.exec(w); 162 | stem = fp[1] + fp[2]; 163 | re2 = new RegExp(mgr1); 164 | if (re2.test(stem)) 165 | w = stem; 166 | } 167 | 168 | // Step 5 169 | re = /^(.+?)e$/; 170 | if (re.test(w)) { 171 | var fp = re.exec(w); 172 | stem = fp[1]; 173 | re = new RegExp(mgr1); 174 | re2 = new RegExp(meq1); 175 | re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); 176 | if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) 177 | w = stem; 178 | } 179 | re = /ll$/; 180 | re2 = new RegExp(mgr1); 181 | if (re.test(w) && re2.test(w)) { 182 | re = /.$/; 183 | w = w.replace(re,""); 184 | } 185 | 186 | // and turn initial Y back to y 187 | if (firstch == "y") 188 | w = firstch.toLowerCase() + w.substr(1); 189 | return w; 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /docs/_build/_static/pygments.css: -------------------------------------------------------------------------------- 1 | pre { line-height: 125%; } 2 | td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } 3 | span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } 4 | td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } 5 | span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } 6 | .highlight .hll { background-color: #ffffcc } 7 | .highlight { background: #f8f8f8; } 8 | .highlight .c { color: #8F5902; font-style: italic } /* Comment */ 9 | .highlight .err { color: #A40000; border: 1px solid #EF2929 } /* Error */ 10 | .highlight .g { color: #000 } /* Generic */ 11 | .highlight .k { color: #204A87; font-weight: bold } /* Keyword */ 12 | .highlight .l { color: #000 } /* Literal */ 13 | .highlight .n { color: #000 } /* Name */ 14 | .highlight .o { color: #CE5C00; font-weight: bold } /* Operator */ 15 | .highlight .x { color: #000 } /* Other */ 16 | .highlight .p { color: #000; font-weight: bold } /* Punctuation */ 17 | .highlight .ch { color: #8F5902; font-style: italic } /* Comment.Hashbang */ 18 | .highlight .cm { color: #8F5902; font-style: italic } /* Comment.Multiline */ 19 | .highlight .cp { color: #8F5902; font-style: italic } /* Comment.Preproc */ 20 | .highlight .cpf { color: #8F5902; font-style: italic } /* Comment.PreprocFile */ 21 | .highlight .c1 { color: #8F5902; font-style: italic } /* Comment.Single */ 22 | .highlight .cs { color: #8F5902; font-style: italic } /* Comment.Special */ 23 | .highlight .gd { color: #A40000 } /* Generic.Deleted */ 24 | .highlight .ge { color: #000; font-style: italic } /* Generic.Emph */ 25 | .highlight .ges { color: #000; font-weight: bold; font-style: italic } /* Generic.EmphStrong */ 26 | .highlight .gr { color: #EF2929 } /* Generic.Error */ 27 | .highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ 28 | .highlight .gi { color: #00A000 } /* Generic.Inserted */ 29 | .highlight .go { color: #000; font-style: italic } /* Generic.Output */ 30 | .highlight .gp { color: #8F5902 } /* Generic.Prompt */ 31 | .highlight .gs { color: #000; font-weight: bold } /* Generic.Strong */ 32 | .highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ 33 | .highlight .gt { color: #A40000; font-weight: bold } /* Generic.Traceback */ 34 | .highlight .kc { color: #204A87; font-weight: bold } /* Keyword.Constant */ 35 | .highlight .kd { color: #204A87; font-weight: bold } /* Keyword.Declaration */ 36 | .highlight .kn { color: #204A87; font-weight: bold } /* Keyword.Namespace */ 37 | .highlight .kp { color: #204A87; font-weight: bold } /* Keyword.Pseudo */ 38 | .highlight .kr { color: #204A87; font-weight: bold } /* Keyword.Reserved */ 39 | .highlight .kt { color: #204A87; font-weight: bold } /* Keyword.Type */ 40 | .highlight .ld { color: #000 } /* Literal.Date */ 41 | .highlight .m { color: #0000CF; font-weight: bold } /* Literal.Number */ 42 | .highlight .s { color: #4E9A06 } /* Literal.String */ 43 | .highlight .na { color: #C4A000 } /* Name.Attribute */ 44 | .highlight .nb { color: #204A87 } /* Name.Builtin */ 45 | .highlight .nc { color: #000 } /* Name.Class */ 46 | .highlight .no { color: #000 } /* Name.Constant */ 47 | .highlight .nd { color: #5C35CC; font-weight: bold } /* Name.Decorator */ 48 | .highlight .ni { color: #CE5C00 } /* Name.Entity */ 49 | .highlight .ne { color: #C00; font-weight: bold } /* Name.Exception */ 50 | .highlight .nf { color: #000 } /* Name.Function */ 51 | .highlight .nl { color: #F57900 } /* Name.Label */ 52 | .highlight .nn { color: #000 } /* Name.Namespace */ 53 | .highlight .nx { color: #000 } /* Name.Other */ 54 | .highlight .py { color: #000 } /* Name.Property */ 55 | .highlight .nt { color: #204A87; font-weight: bold } /* Name.Tag */ 56 | .highlight .nv { color: #000 } /* Name.Variable */ 57 | .highlight .ow { color: #204A87; font-weight: bold } /* Operator.Word */ 58 | .highlight .pm { color: #000; font-weight: bold } /* Punctuation.Marker */ 59 | .highlight .w { color: #F8F8F8 } /* Text.Whitespace */ 60 | .highlight .mb { color: #0000CF; font-weight: bold } /* Literal.Number.Bin */ 61 | .highlight .mf { color: #0000CF; font-weight: bold } /* Literal.Number.Float */ 62 | .highlight .mh { color: #0000CF; font-weight: bold } /* Literal.Number.Hex */ 63 | .highlight .mi { color: #0000CF; font-weight: bold } /* Literal.Number.Integer */ 64 | .highlight .mo { color: #0000CF; font-weight: bold } /* Literal.Number.Oct */ 65 | .highlight .sa { color: #4E9A06 } /* Literal.String.Affix */ 66 | .highlight .sb { color: #4E9A06 } /* Literal.String.Backtick */ 67 | .highlight .sc { color: #4E9A06 } /* Literal.String.Char */ 68 | .highlight .dl { color: #4E9A06 } /* Literal.String.Delimiter */ 69 | .highlight .sd { color: #8F5902; font-style: italic } /* Literal.String.Doc */ 70 | .highlight .s2 { color: #4E9A06 } /* Literal.String.Double */ 71 | .highlight .se { color: #4E9A06 } /* Literal.String.Escape */ 72 | .highlight .sh { color: #4E9A06 } /* Literal.String.Heredoc */ 73 | .highlight .si { color: #4E9A06 } /* Literal.String.Interpol */ 74 | .highlight .sx { color: #4E9A06 } /* Literal.String.Other */ 75 | .highlight .sr { color: #4E9A06 } /* Literal.String.Regex */ 76 | .highlight .s1 { color: #4E9A06 } /* Literal.String.Single */ 77 | .highlight .ss { color: #4E9A06 } /* Literal.String.Symbol */ 78 | .highlight .bp { color: #3465A4 } /* Name.Builtin.Pseudo */ 79 | .highlight .fm { color: #000 } /* Name.Function.Magic */ 80 | .highlight .vc { color: #000 } /* Name.Variable.Class */ 81 | .highlight .vg { color: #000 } /* Name.Variable.Global */ 82 | .highlight .vi { color: #000 } /* Name.Variable.Instance */ 83 | .highlight .vm { color: #000 } /* Name.Variable.Magic */ 84 | .highlight .il { color: #0000CF; font-weight: bold } /* Literal.Number.Integer.Long */ 85 | -------------------------------------------------------------------------------- /docs/_build/_static/sphinx_highlight.js: -------------------------------------------------------------------------------- 1 | /* Highlighting utilities for Sphinx HTML documentation. */ 2 | "use strict"; 3 | 4 | const SPHINX_HIGHLIGHT_ENABLED = true 5 | 6 | /** 7 | * highlight a given string on a node by wrapping it in 8 | * span elements with the given class name. 9 | */ 10 | const _highlight = (node, addItems, text, className) => { 11 | if (node.nodeType === Node.TEXT_NODE) { 12 | const val = node.nodeValue; 13 | const parent = node.parentNode; 14 | const pos = val.toLowerCase().indexOf(text); 15 | if ( 16 | pos >= 0 && 17 | !parent.classList.contains(className) && 18 | !parent.classList.contains("nohighlight") 19 | ) { 20 | let span; 21 | 22 | const closestNode = parent.closest("body, svg, foreignObject"); 23 | const isInSVG = closestNode && closestNode.matches("svg"); 24 | if (isInSVG) { 25 | span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); 26 | } else { 27 | span = document.createElement("span"); 28 | span.classList.add(className); 29 | } 30 | 31 | span.appendChild(document.createTextNode(val.substr(pos, text.length))); 32 | const rest = document.createTextNode(val.substr(pos + text.length)); 33 | parent.insertBefore( 34 | span, 35 | parent.insertBefore( 36 | rest, 37 | node.nextSibling 38 | ) 39 | ); 40 | node.nodeValue = val.substr(0, pos); 41 | /* There may be more occurrences of search term in this node. So call this 42 | * function recursively on the remaining fragment. 43 | */ 44 | _highlight(rest, addItems, text, className); 45 | 46 | if (isInSVG) { 47 | const rect = document.createElementNS( 48 | "http://www.w3.org/2000/svg", 49 | "rect" 50 | ); 51 | const bbox = parent.getBBox(); 52 | rect.x.baseVal.value = bbox.x; 53 | rect.y.baseVal.value = bbox.y; 54 | rect.width.baseVal.value = bbox.width; 55 | rect.height.baseVal.value = bbox.height; 56 | rect.setAttribute("class", className); 57 | addItems.push({ parent: parent, target: rect }); 58 | } 59 | } 60 | } else if (node.matches && !node.matches("button, select, textarea")) { 61 | node.childNodes.forEach((el) => _highlight(el, addItems, text, className)); 62 | } 63 | }; 64 | const _highlightText = (thisNode, text, className) => { 65 | let addItems = []; 66 | _highlight(thisNode, addItems, text, className); 67 | addItems.forEach((obj) => 68 | obj.parent.insertAdjacentElement("beforebegin", obj.target) 69 | ); 70 | }; 71 | 72 | /** 73 | * Small JavaScript module for the documentation. 74 | */ 75 | const SphinxHighlight = { 76 | 77 | /** 78 | * highlight the search words provided in localstorage in the text 79 | */ 80 | highlightSearchWords: () => { 81 | if (!SPHINX_HIGHLIGHT_ENABLED) return; // bail if no highlight 82 | 83 | // get and clear terms from localstorage 84 | const url = new URL(window.location); 85 | const highlight = 86 | localStorage.getItem("sphinx_highlight_terms") 87 | || url.searchParams.get("highlight") 88 | || ""; 89 | localStorage.removeItem("sphinx_highlight_terms") 90 | url.searchParams.delete("highlight"); 91 | window.history.replaceState({}, "", url); 92 | 93 | // get individual terms from highlight string 94 | const terms = highlight.toLowerCase().split(/\s+/).filter(x => x); 95 | if (terms.length === 0) return; // nothing to do 96 | 97 | // There should never be more than one element matching "div.body" 98 | const divBody = document.querySelectorAll("div.body"); 99 | const body = divBody.length ? divBody[0] : document.querySelector("body"); 100 | window.setTimeout(() => { 101 | terms.forEach((term) => _highlightText(body, term, "highlighted")); 102 | }, 10); 103 | 104 | const searchBox = document.getElementById("searchbox"); 105 | if (searchBox === null) return; 106 | searchBox.appendChild( 107 | document 108 | .createRange() 109 | .createContextualFragment( 110 | '" 114 | ) 115 | ); 116 | }, 117 | 118 | /** 119 | * helper function to hide the search marks again 120 | */ 121 | hideSearchWords: () => { 122 | document 123 | .querySelectorAll("#searchbox .highlight-link") 124 | .forEach((el) => el.remove()); 125 | document 126 | .querySelectorAll("span.highlighted") 127 | .forEach((el) => el.classList.remove("highlighted")); 128 | localStorage.removeItem("sphinx_highlight_terms") 129 | }, 130 | 131 | initEscapeListener: () => { 132 | // only install a listener if it is really needed 133 | if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) return; 134 | 135 | document.addEventListener("keydown", (event) => { 136 | // bail for input elements 137 | if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; 138 | // bail with special keys 139 | if (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) return; 140 | if (DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS && (event.key === "Escape")) { 141 | SphinxHighlight.hideSearchWords(); 142 | event.preventDefault(); 143 | } 144 | }); 145 | }, 146 | }; 147 | 148 | _ready(() => { 149 | /* Do not call highlightSearchWords() when we are on the search page. 150 | * It will highlight words from the *previous* search query. 151 | */ 152 | if (typeof Search === "undefined") SphinxHighlight.highlightSearchWords(); 153 | SphinxHighlight.initEscapeListener(); 154 | }); 155 | -------------------------------------------------------------------------------- /docs/_build/searchindex.js: -------------------------------------------------------------------------------- 1 | Search.setIndex({"alltitles":{"API Reference":[[2,null]],"Classes":[[0,"classes"],[1,"classes"]],"Contents:":[[3,null]],"Module Contents":[[0,"module-contents"]],"Package Contents":[[1,"package-contents"]],"Submodules":[[1,"submodules"]],"codalpy":[[1,null]],"codalpy documentation":[[3,null]],"codalpy.codal":[[0,null]]},"docnames":["autoapi/codalpy/codal/index","autoapi/codalpy/index","autoapi/index","index"],"envversion":{"sphinx":65,"sphinx.domains.c":3,"sphinx.domains.changeset":1,"sphinx.domains.citation":1,"sphinx.domains.cpp":9,"sphinx.domains.index":1,"sphinx.domains.javascript":3,"sphinx.domains.math":2,"sphinx.domains.python":4,"sphinx.domains.rst":2,"sphinx.domains.std":2,"sphinx.ext.viewcode":1},"filenames":["autoapi/codalpy/codal/index.rst","autoapi/codalpy/index.rst","autoapi/index.rst","index.rst"],"indexentries":{"balance_sheet() (codal method)":[[0,"codalpy.codal.Codal.balance_sheet",false],[1,"codalpy.Codal.balance_sheet",false]],"codal (class in codalpy)":[[1,"codalpy.Codal",false]],"codal (class in codalpy.codal)":[[0,"codalpy.codal.Codal",false]],"codalpy":[[1,"module-codalpy",false]],"codalpy.codal":[[0,"module-codalpy.codal",false]],"from_jdate (codal property)":[[0,"codalpy.codal.Codal.from_jdate",false],[1,"codalpy.Codal.from_jdate",false]],"fund_monthly_portfolio() (codal method)":[[0,"codalpy.codal.Codal.fund_monthly_portfolio",false],[1,"codalpy.Codal.fund_monthly_portfolio",false]],"income_statement() (codal method)":[[0,"codalpy.codal.Codal.income_statement",false],[1,"codalpy.Codal.income_statement",false]],"issuer (codal property)":[[0,"codalpy.codal.Codal.issuer",false],[1,"codalpy.Codal.issuer",false]],"letter() (codal method)":[[0,"codalpy.codal.Codal.letter",false],[1,"codalpy.Codal.letter",false]],"module":[[0,"module-codalpy.codal",false],[1,"module-codalpy",false]],"monthly_activity() (codal method)":[[0,"codalpy.codal.Codal.monthly_activity",false],[1,"codalpy.Codal.monthly_activity",false]],"query (codal property)":[[0,"codalpy.codal.Codal.query",false],[1,"codalpy.Codal.query",false]],"supported_issuers() (codal static method)":[[0,"codalpy.codal.Codal.supported_issuers",false],[1,"codalpy.Codal.supported_issuers",false]],"to_jdate (codal property)":[[0,"codalpy.codal.Codal.to_jdate",false],[1,"codalpy.Codal.to_jdate",false]]},"objects":{"":[[1,0,0,"-","codalpy"]],"codalpy":[[1,1,1,"","Codal"],[0,0,0,"-","codal"]],"codalpy.Codal":[[1,2,1,"","balance_sheet"],[1,3,1,"","from_jdate"],[1,2,1,"","fund_monthly_portfolio"],[1,2,1,"","income_statement"],[1,3,1,"","issuer"],[1,2,1,"","letter"],[1,2,1,"","monthly_activity"],[1,3,1,"","query"],[1,2,1,"","supported_issuers"],[1,3,1,"","to_jdate"]],"codalpy.codal":[[0,1,1,"","Codal"]],"codalpy.codal.Codal":[[0,2,1,"","balance_sheet"],[0,3,1,"","from_jdate"],[0,2,1,"","fund_monthly_portfolio"],[0,2,1,"","income_statement"],[0,3,1,"","issuer"],[0,2,1,"","letter"],[0,2,1,"","monthly_activity"],[0,3,1,"","query"],[0,2,1,"","supported_issuers"],[0,3,1,"","to_jdate"]]},"objnames":{"0":["py","module","Python module"],"1":["py","class","Python class"],"2":["py","method","Python method"],"3":["py","property","Python property"]},"objtypes":{"0":"py:module","1":"py:class","2":"py:method","3":"py:property"},"terms":{"0":[0,1],"01":[0,1],"04":[0,1],"1":2,"102290130720":[0,1],"117032944":[0,1],"12":[0,1],"123719463000":[0,1],"137950282800":[0,1],"1401":[0,1],"1404":[0,1],"140495106806":[0,1],"1405":[0,1],"168768973101":[0,1],"175805992152":[0,1],"18":[0,1],"2":[0,1],"24500000":[0,1],"266248175":[0,1],"29":[0,1],"310735053213":[0,1],"363313257531":[0,1],"38000000":[0,1],"427355209792":[0,1],"428681824109":[0,1],"42921313500":[0,1],"58949663":[0,1],"603":[0,1],"619056648665":[0,1],"79400000":[0,1],"84043466":[0,1],"853755414625":[0,1],"982697425906":[0,1],"A":[0,1],"The":[0,1],"add":3,"alia":[0,1],"api":3,"attachment_url":[0,1],"auto":2,"autoapi":2,"balance_sheet":[0,1],"cagegori":[0,1],"categori":[0,1],"codal":[1,2],"codalpi":2,"contain":2,"creat":2,"data":[0,1],"datafram":[0,1],"datasourceresult":[0,1],"detail":3,"div":[0,1],"document":2,"etf":[0,1],"exampl":[0,1],"from":[0,1],"from_jdat":[0,1],"fund":[0,1],"fund_monthly_portfolio":[0,1],"gener":2,"http":[0,1],"i64":[0,1],"import":[0,1],"income_stat":[0,1],"ir":[0,1],"issuer":[0,1],"issuercategori":[0,1],"issuerdtyp":[0,1],"letter":[0,1],"list":[0,1],"model":[0,1],"monthly_act":[0,1],"name":[0,1],"net_proceeds_beg":[0,1],"page":2,"polar":[0,1],"properti":[0,1],"queri":[0,1],"refer":3,"report":[0,1],"restructuredtext":3,"return":[0,1],"see":3,"shape":[0,1],"sourc":[0,1],"sphinx":2,"static":[0,1],"str":[0,1],"supported_issu":[0,1],"symbol":[0,1],"syntax":3,"thi":2,"titl":[0,1],"to_jdat":[0,1],"total_cost_beg":[0,1],"type":[0,1],"url":[0,1],"us":3,"util":[0,1],"volume_beg":[0,1],"www":[0,1],"your":3,"\u0622\u0632\u0627\u062f\u06af\u0627\u0646":[0,1],"\u0622\u0647\u0646":[0,1],"\u0627\u0642\u062a\u0635\u0627\u062f\u06cc":[0,1],"\u0627\u0644\u0628\u0631\u0632":[0,1],"\u0627\u0644\u0628\u0631\u0632\u062f\u0627\u0631\u0648":[0,1],"\u0627\u0644\u062d\u0627\u0648\u06cc":[0,1],"\u0627\u0644\u06a9\u062a\u0631\u06cc\u06a9":[0,1],"\u0627\u0647\u0631\u0645":[0,1],"\u0627\u0647\u0631\u0645\u06cc":[0,1],"\u0627\u06cc\u0631\u0627\u0646\u06cc\u0627\u0646":[0,1],"\u0628\u0647":[0,1],"\u0628\u0647\u062a":[0,1],"\u062a\u0627\u06cc\u0631":[0,1],"\u062a\u0648\u0627\u0646":[0,1],"\u062d":[0,1],"\u062e\u0648\u062f\u0631\u0648":[0,1],"\u062e\u0648\u062f\u06a9\u0641\u0627\u06cc\u06cc":[0,1],"\u062f\u0627\u062f\u0647":[0,1],"\u062f\u0627\u0645\u062f\u0627\u0631\u06cc":[0,1],"\u0631\u0648":[0,1],"\u0633\u0631\u0645\u0627\u06cc":[0,1],"\u0633\u0631\u0645\u0627\u06cc\u0647":[0,1],"\u0633\u0646\u06af":[0,1],"\u0633\u0647\u0627\u0645":[0,1],"\u0633\u0647\u0627\u0645\u06cc":[0,1],"\u0634\u0631\u0642":[0,1],"\u0634\u067e\u062f\u06cc\u0633":[0,1],"\u0635\u0646\u062f\u0648\u0642":[0,1],"\u0635\u0648\u0631\u062a":[0,1],"\u0639\u0645\u0644\u06a9\u0631\u062f":[0,1],"\u063a\u062f\u06cc\u0631":[0,1],"\u0641\u0639\u0627\u0644\u06cc\u062a":[0,1],"\u0641\u0648\u0644\u0627\u062f":[0,1],"\u0641\u06a9\u0627":[0,1],"\u0645\u0627\u0644\u06cc":[0,1],"\u0645\u0627\u0647\u0627\u0646\u0647":[0,1],"\u0645\u0641\u06cc\u062f":[0,1],"\u0645\u06cc\u062f\u0647":[0,1],"\u0645\u06cc\u0634\u0647":[0,1],"\u0646\u0627\u0634\u0631\u0647\u0627\u06cc\u06cc":[0,1],"\u0647\u0627\u06cc":[0,1],"\u0647\u0644\u062f\u06cc\u0646\u06af":[0,1],"\u0648":[0,1],"\u0648\u0636\u0639\u06cc\u062a":[0,1],"\u067e\u0634\u062a\u06cc\u0628\u0627\u0646\u06cc":[0,1],"\u067e\u0648\u0631\u062a\u0641\u0648\u06cc":[0,1],"\u06a9\u0627\u0631\u06cc\u0632\u0645\u0627":[0,1],"\u06a9\u0634\u062a":[0,1],"\u06a9\u0647":[0,1],"\u06a9\u0648\u06cc\u0631":[0,1],"\u06af\u0630\u0627\u0631\u06cc":[0,1],"\u06af\u0647\u0631\u0632\u0645\u06cc\u0646":[0,1]},"titles":["codalpy.codal","codalpy","API Reference","codalpy documentation"],"titleterms":{"api":2,"class":[0,1],"codal":0,"codalpi":[0,1,3],"content":[0,1,3],"document":3,"modul":0,"packag":1,"refer":2,"submodul":1}}) 2 | -------------------------------------------------------------------------------- /docs/_build/_sources/autoapi/codalpy/codal/index.rst.txt: -------------------------------------------------------------------------------- 1 | codalpy.codal 2 | ============= 3 | 4 | .. py:module:: codalpy.codal 5 | 6 | 7 | Classes 8 | ------- 9 | 10 | .. autoapisummary:: 11 | 12 | codalpy.codal.Codal 13 | 14 | 15 | Module Contents 16 | --------------- 17 | 18 | .. py:class:: Codal(issuer: str, from_jdate: str, to_jdate: str) 19 | 20 | .. py:property:: issuer 21 | 22 | 23 | .. py:property:: from_jdate 24 | 25 | 26 | .. py:property:: to_jdate 27 | 28 | 29 | .. py:property:: query 30 | 31 | 32 | .. py:method:: supported_issuers(cagegory: list[codalpy.utils.issuer.IssuerCategory]) -> list[codalpy.utils.issuer.IssuerDType] 33 | :staticmethod: 34 | 35 | 36 | .. raw:: html 37 | 38 |
39 | ناشرهایی که پشتیبانی میشه رو بهت میده. 40 |
41 | 42 | :param cagegory: The category of the issuer. 43 | :type cagegory: list[IssuerCategory] 44 | 45 | :rtype: list[IssuerDType] 46 | 47 | .. rubric:: Example 48 | 49 | >>> from codalpy import Codal, IssuerCategory 50 | >>> Codal.supported_issuers([IssuerCategory.FUND])[:2] 51 | [IssuerDType(name='سهامی اهرمی کاریزما', symbol='اهرم', alias='اهرم', category=), 52 | IssuerDType(name='سهامی اهرمی مفید', symbol='توان', alias='توان', category=)] 53 | 54 | 55 | 56 | .. py:method:: letter() -> list[codalpy.models.Letter] 57 | 58 | 59 | .. py:method:: income_statement() -> list[codalpy.models.DataSourceResult] 60 | 61 | .. raw:: html 62 | 63 |
64 | داده هایٍ صورت-عملکردِ مالی رو بهت میده 65 |
66 | 67 | :rtype: list[DataSourceResult] 68 | 69 | .. rubric:: Example 70 | 71 | >>> from codalpy import Codal 72 | >>> codal = Codal( 73 | issuer = "شپدیس", 74 | from_jdate = "1401/01/01", 75 | to_jdate = "1404/12/29" 76 | ) 77 | >>> data = codal.income_statement() 78 | 79 | 80 | 81 | .. py:method:: balance_sheet() -> list[codalpy.models.DataSourceResult] 82 | 83 | .. raw:: html 84 | 85 |
86 | داده هایٍ صورت-وضعیتِ مالی رو بهت میده 87 |
88 | 89 | :rtype: list[DataSourceResult] 90 | 91 | .. rubric:: Example 92 | 93 | >>> from codalpy import Codal 94 | >>> codal = Codal( 95 | issuer = "شپدیس", 96 | from_jdate = "1401/01/01", 97 | to_jdate = "1404/12/29" 98 | ) 99 | >>> data = codal.balance_sheet() 100 | 101 | 102 | 103 | .. py:method:: monthly_activity() -> list[codalpy.models.DataSourceResult] 104 | 105 | .. raw:: html 106 | 107 |
108 | داده هایٍ فعالیتِ ماهانه رو بهت میده 109 |
110 | 111 | :rtype: list[DataSourceResult] 112 | 113 | .. rubric:: Example 114 | 115 | >>> from codalpy import Codal 116 | >>> codal = Codal( 117 | issuer = "شپدیس", 118 | from_jdate = "1404/04/01", 119 | to_jdate = "1404/12/29" 120 | ) 121 | >>> data = codal.monthly_activity() 122 | 123 | 124 | 125 | .. py:method:: fund_monthly_portfolio() -> polars.DataFrame 126 | 127 | .. raw:: html 128 | 129 |
130 | پورتفوی سهامِ صندوق‌هایِ ETF رو به صورتِ‌ ماهانه بهت میده. 131 |
132 | 133 | :rtype: polars.DataFrame 134 | 135 | .. rubric:: Example 136 | 137 | >>> from codalpy import Codal 138 | >>> codal = Codal(issuer = "اهرم", from_jdate= "1404-04-04", to_jdate="1404-06-06") 139 | >>> codal.fund_monthly_portfolio() 140 | shape: (603, 18) 141 | ┌──────────────────────────────┬────────────┬────────────────┬──────────────────┬───┬────────┬─────────────────────────────────┬─────────────────────────────────┬─────────────────────────────────┐ 142 | │ name ┆ volume_beg ┆ total_cost_beg ┆ net_proceeds_beg ┆ … ┆ symbol ┆ title ┆ url ┆ attachment_url │ 143 | │ --- ┆ --- ┆ --- ┆ --- ┆ ┆ --- ┆ --- ┆ --- ┆ --- │ 144 | │ str ┆ i64 ┆ i64 ┆ i64 ┆ ┆ str ┆ str ┆ str ┆ str │ 145 | ╞══════════════════════════════╪════════════╪════════════════╪══════════════════╪═══╪════════╪═════════════════════════════════╪═════════════════════════════════╪═════════════════════════════════╡ 146 | │ آهن و فولاد غدیر ایرانیان ┆ 24500000 ┆ 140495106806 ┆ 123719463000 ┆ … ┆ اهرم ┆ صورت وضعیت پورتفوی صندوق سرمای… ┆ https://www.codal.ir/Reports/A… ┆ https://www.codal.ir/Reports/A… │ 147 | │ اقتصادی و خودکفایی آزادگان ┆ 58949663 ┆ 428681824109 ┆ 363313257531 ┆ … ┆ اهرم ┆ صورت وضعیت پورتفوی صندوق سرمای… ┆ https://www.codal.ir/Reports/A… ┆ https://www.codal.ir/Reports/A… │ 148 | │ البرزدارو ┆ 266248175 ┆ 853755414625 ┆ 982697425906 ┆ … ┆ اهرم ┆ صورت وضعیت پورتفوی صندوق سرمای… ┆ https://www.codal.ir/Reports/A… ┆ https://www.codal.ir/Reports/A… │ 149 | │ الحاوی ┆ 79400000 ┆ 175805992152 ┆ 102290130720 ┆ … ┆ اهرم ┆ صورت وضعیت پورتفوی صندوق سرمای… ┆ https://www.codal.ir/Reports/A… ┆ https://www.codal.ir/Reports/A… │ 150 | │ الکتریک‌ خودرو شرق‌ ┆ 117032944 ┆ 427355209792 ┆ 310735053213 ┆ … ┆ اهرم ┆ صورت وضعیت پورتفوی صندوق سرمای… ┆ https://www.codal.ir/Reports/A… ┆ https://www.codal.ir/Reports/A… │ 151 | │ … ┆ … ┆ … ┆ … ┆ … ┆ … ┆ … ┆ … ┆ … │ 152 | │ کشت و دامداری فکا ┆ 38000000 ┆ 42921313500 ┆ 137950282800 ┆ … ┆ اهرم ┆ صورت وضعیت پورتفوی صندوق سرمای… ┆ https://www.codal.ir/Reports/A… ┆ https://www.codal.ir/Reports/A… │ 153 | │ کویر تایر ┆ 84043466 ┆ 168768973101 ┆ 619056648665 ┆ … ┆ اهرم ┆ صورت وضعیت پورتفوی صندوق سرمای… ┆ https://www.codal.ir/Reports/A… ┆ https://www.codal.ir/Reports/A… │ 154 | │ ح . سرمایه گذاری‌البرز(هلدینگ‌ ┆ 0 ┆ 0 ┆ 0 ┆ … ┆ اهرم ┆ صورت وضعیت پورتفوی صندوق سرمای… ┆ https://www.codal.ir/Reports/A… ┆ https://www.codal.ir/Reports/A… │ 155 | │ سنگ آهن گهرزمین ┆ 0 ┆ 0 ┆ 0 ┆ … ┆ اهرم ┆ صورت وضعیت پورتفوی صندوق سرمای… ┆ https://www.codal.ir/Reports/A… ┆ https://www.codal.ir/Reports/A… │ 156 | │ ح . سنگ آهن گهرزمین ┆ 0 ┆ 0 ┆ 0 ┆ … ┆ اهرم ┆ صورت وضعیت پورتفوی صندوق سرمای… ┆ https://www.codal.ir/Reports/A… ┆ https://www.codal.ir/Reports/A… │ 157 | └──────────────────────────────┴────────────┴────────────────┴──────────────────┴───┴────────┴─────────────────────────────────┴─────────────────────────────────┴─────────────────────────────────┘ 158 | -------------------------------------------------------------------------------- /docs/_build/_sources/autoapi/codalpy/index.rst.txt: -------------------------------------------------------------------------------- 1 | codalpy 2 | ======= 3 | 4 | .. py:module:: codalpy 5 | 6 | 7 | Submodules 8 | ---------- 9 | 10 | .. toctree:: 11 | :maxdepth: 1 12 | 13 | /autoapi/codalpy/codal/index 14 | /autoapi/codalpy/models/index 15 | 16 | 17 | Classes 18 | ------- 19 | 20 | .. autoapisummary:: 21 | 22 | codalpy.Codal 23 | 24 | 25 | Package Contents 26 | ---------------- 27 | 28 | .. py:class:: Codal(issuer: str, from_jdate: str, to_jdate: str) 29 | 30 | .. py:property:: issuer 31 | 32 | 33 | .. py:property:: from_jdate 34 | 35 | 36 | .. py:property:: to_jdate 37 | 38 | 39 | .. py:property:: query 40 | 41 | 42 | .. py:method:: supported_issuers(cagegory: list[codalpy.utils.issuer.IssuerCategory]) -> list[codalpy.utils.issuer.IssuerDType] 43 | :staticmethod: 44 | 45 | 46 | .. raw:: html 47 | 48 |
49 | ناشرهایی که پشتیبانی میشه رو بهت میده. 50 |
51 | 52 | :param cagegory: The category of the issuer. 53 | :type cagegory: list[IssuerCategory] 54 | 55 | :rtype: list[IssuerDType] 56 | 57 | .. rubric:: Example 58 | 59 | >>> from codalpy import Codal, IssuerCategory 60 | >>> Codal.supported_issuers([IssuerCategory.FUND])[:2] 61 | [IssuerDType(name='سهامی اهرمی کاریزما', symbol='اهرم', alias='اهرم', category=), 62 | IssuerDType(name='سهامی اهرمی مفید', symbol='توان', alias='توان', category=)] 63 | 64 | 65 | 66 | .. py:method:: letter() -> list[codalpy.models.Letter] 67 | 68 | 69 | .. py:method:: income_statement() -> list[codalpy.models.DataSourceResult] 70 | 71 | .. raw:: html 72 | 73 |
74 | داده هایٍ صورت-عملکردِ مالی رو بهت میده 75 |
76 | 77 | :rtype: list[DataSourceResult] 78 | 79 | .. rubric:: Example 80 | 81 | >>> from codalpy import Codal 82 | >>> codal = Codal( 83 | issuer = "شپدیس", 84 | from_jdate = "1401/01/01", 85 | to_jdate = "1404/12/29" 86 | ) 87 | >>> data = codal.income_statement() 88 | 89 | 90 | 91 | .. py:method:: balance_sheet() -> list[codalpy.models.DataSourceResult] 92 | 93 | .. raw:: html 94 | 95 |
96 | داده هایٍ صورت-وضعیتِ مالی رو بهت میده 97 |
98 | 99 | :rtype: list[DataSourceResult] 100 | 101 | .. rubric:: Example 102 | 103 | >>> from codalpy import Codal 104 | >>> codal = Codal( 105 | issuer = "شپدیس", 106 | from_jdate = "1401/01/01", 107 | to_jdate = "1404/12/29" 108 | ) 109 | >>> data = codal.balance_sheet() 110 | 111 | 112 | 113 | .. py:method:: monthly_activity() -> list[codalpy.models.DataSourceResult] 114 | 115 | .. raw:: html 116 | 117 |
118 | داده هایٍ فعالیتِ ماهانه رو بهت میده 119 |
120 | 121 | :rtype: list[DataSourceResult] 122 | 123 | .. rubric:: Example 124 | 125 | >>> from codalpy import Codal 126 | >>> codal = Codal( 127 | issuer = "شپدیس", 128 | from_jdate = "1404/04/01", 129 | to_jdate = "1404/12/29" 130 | ) 131 | >>> data = codal.monthly_activity() 132 | 133 | 134 | 135 | .. py:method:: fund_monthly_portfolio() -> polars.DataFrame 136 | 137 | .. raw:: html 138 | 139 |
140 | پورتفوی سهامِ صندوق‌هایِ ETF رو به صورتِ‌ ماهانه بهت میده. 141 |
142 | 143 | :rtype: polars.DataFrame 144 | 145 | .. rubric:: Example 146 | 147 | >>> from codalpy import Codal 148 | >>> codal = Codal(issuer = "اهرم", from_jdate= "1404-04-04", to_jdate="1404-06-06") 149 | >>> codal.fund_monthly_portfolio() 150 | shape: (603, 18) 151 | ┌──────────────────────────────┬────────────┬────────────────┬──────────────────┬───┬────────┬─────────────────────────────────┬─────────────────────────────────┬─────────────────────────────────┐ 152 | │ name ┆ volume_beg ┆ total_cost_beg ┆ net_proceeds_beg ┆ … ┆ symbol ┆ title ┆ url ┆ attachment_url │ 153 | │ --- ┆ --- ┆ --- ┆ --- ┆ ┆ --- ┆ --- ┆ --- ┆ --- │ 154 | │ str ┆ i64 ┆ i64 ┆ i64 ┆ ┆ str ┆ str ┆ str ┆ str │ 155 | ╞══════════════════════════════╪════════════╪════════════════╪══════════════════╪═══╪════════╪═════════════════════════════════╪═════════════════════════════════╪═════════════════════════════════╡ 156 | │ آهن و فولاد غدیر ایرانیان ┆ 24500000 ┆ 140495106806 ┆ 123719463000 ┆ … ┆ اهرم ┆ صورت وضعیت پورتفوی صندوق سرمای… ┆ https://www.codal.ir/Reports/A… ┆ https://www.codal.ir/Reports/A… │ 157 | │ اقتصادی و خودکفایی آزادگان ┆ 58949663 ┆ 428681824109 ┆ 363313257531 ┆ … ┆ اهرم ┆ صورت وضعیت پورتفوی صندوق سرمای… ┆ https://www.codal.ir/Reports/A… ┆ https://www.codal.ir/Reports/A… │ 158 | │ البرزدارو ┆ 266248175 ┆ 853755414625 ┆ 982697425906 ┆ … ┆ اهرم ┆ صورت وضعیت پورتفوی صندوق سرمای… ┆ https://www.codal.ir/Reports/A… ┆ https://www.codal.ir/Reports/A… │ 159 | │ الحاوی ┆ 79400000 ┆ 175805992152 ┆ 102290130720 ┆ … ┆ اهرم ┆ صورت وضعیت پورتفوی صندوق سرمای… ┆ https://www.codal.ir/Reports/A… ┆ https://www.codal.ir/Reports/A… │ 160 | │ الکتریک‌ خودرو شرق‌ ┆ 117032944 ┆ 427355209792 ┆ 310735053213 ┆ … ┆ اهرم ┆ صورت وضعیت پورتفوی صندوق سرمای… ┆ https://www.codal.ir/Reports/A… ┆ https://www.codal.ir/Reports/A… │ 161 | │ … ┆ … ┆ … ┆ … ┆ … ┆ … ┆ … ┆ … ┆ … │ 162 | │ کشت و دامداری فکا ┆ 38000000 ┆ 42921313500 ┆ 137950282800 ┆ … ┆ اهرم ┆ صورت وضعیت پورتفوی صندوق سرمای… ┆ https://www.codal.ir/Reports/A… ┆ https://www.codal.ir/Reports/A… │ 163 | │ کویر تایر ┆ 84043466 ┆ 168768973101 ┆ 619056648665 ┆ … ┆ اهرم ┆ صورت وضعیت پورتفوی صندوق سرمای… ┆ https://www.codal.ir/Reports/A… ┆ https://www.codal.ir/Reports/A… │ 164 | │ ح . سرمایه گذاری‌البرز(هلدینگ‌ ┆ 0 ┆ 0 ┆ 0 ┆ … ┆ اهرم ┆ صورت وضعیت پورتفوی صندوق سرمای… ┆ https://www.codal.ir/Reports/A… ┆ https://www.codal.ir/Reports/A… │ 165 | │ سنگ آهن گهرزمین ┆ 0 ┆ 0 ┆ 0 ┆ … ┆ اهرم ┆ صورت وضعیت پورتفوی صندوق سرمای… ┆ https://www.codal.ir/Reports/A… ┆ https://www.codal.ir/Reports/A… │ 166 | │ ح . سنگ آهن گهرزمین ┆ 0 ┆ 0 ┆ 0 ┆ … ┆ اهرم ┆ صورت وضعیت پورتفوی صندوق سرمای… ┆ https://www.codal.ir/Reports/A… ┆ https://www.codal.ir/Reports/A… │ 167 | └──────────────────────────────┴────────────┴────────────────┴──────────────────┴───┴────────┴─────────────────────────────────┴─────────────────────────────────┴─────────────────────────────────┘ 168 | -------------------------------------------------------------------------------- /docs/_build/_static/clipboard.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * clipboard.js v2.0.8 3 | * https://clipboardjs.com/ 4 | * 5 | * Licensed MIT © Zeno Rocha 6 | */ 7 | !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return n={686:function(t,e,n){"use strict";n.d(e,{default:function(){return o}});var e=n(279),i=n.n(e),e=n(370),u=n.n(e),e=n(817),c=n.n(e);function a(t){try{return document.execCommand(t)}catch(t){return}}var f=function(t){t=c()(t);return a("cut"),t};var l=function(t){var e,n,o,r=1 62 | ${messages[locale]['copy_success']} 63 | 64 | 65 | ` 66 | 67 | // If the user specified their own SVG use that, otherwise use the default 68 | let iconCopy = ``; 69 | if (!iconCopy) { 70 | iconCopy = ` 71 | ${messages[locale]['copy_to_clipboard']} 72 | 73 | 74 | 75 | ` 76 | } 77 | 78 | /** 79 | * Set up copy/paste for code blocks 80 | */ 81 | 82 | const runWhenDOMLoaded = cb => { 83 | if (document.readyState != 'loading') { 84 | cb() 85 | } else if (document.addEventListener) { 86 | document.addEventListener('DOMContentLoaded', cb) 87 | } else { 88 | document.attachEvent('onreadystatechange', function() { 89 | if (document.readyState == 'complete') cb() 90 | }) 91 | } 92 | } 93 | 94 | const codeCellId = index => `codecell${index}` 95 | 96 | // Clears selected text since ClipboardJS will select the text when copying 97 | const clearSelection = () => { 98 | if (window.getSelection) { 99 | window.getSelection().removeAllRanges() 100 | } else if (document.selection) { 101 | document.selection.empty() 102 | } 103 | } 104 | 105 | // Changes tooltip text for a moment, then changes it back 106 | // We want the timeout of our `success` class to be a bit shorter than the 107 | // tooltip and icon change, so that we can hide the icon before changing back. 108 | var timeoutIcon = 2000; 109 | var timeoutSuccessClass = 1500; 110 | 111 | const temporarilyChangeTooltip = (el, oldText, newText) => { 112 | el.setAttribute('data-tooltip', newText) 113 | el.classList.add('success') 114 | // Remove success a little bit sooner than we change the tooltip 115 | // So that we can use CSS to hide the copybutton first 116 | setTimeout(() => el.classList.remove('success'), timeoutSuccessClass) 117 | setTimeout(() => el.setAttribute('data-tooltip', oldText), timeoutIcon) 118 | } 119 | 120 | // Changes the copy button icon for two seconds, then changes it back 121 | const temporarilyChangeIcon = (el) => { 122 | el.innerHTML = iconCheck; 123 | setTimeout(() => {el.innerHTML = iconCopy}, timeoutIcon) 124 | } 125 | 126 | const addCopyButtonToCodeCells = () => { 127 | // If ClipboardJS hasn't loaded, wait a bit and try again. This 128 | // happens because we load ClipboardJS asynchronously. 129 | if (window.ClipboardJS === undefined) { 130 | setTimeout(addCopyButtonToCodeCells, 250) 131 | return 132 | } 133 | 134 | // Add copybuttons to all of our code cells 135 | const COPYBUTTON_SELECTOR = 'div.highlight pre'; 136 | const codeCells = document.querySelectorAll(COPYBUTTON_SELECTOR) 137 | codeCells.forEach((codeCell, index) => { 138 | const id = codeCellId(index) 139 | codeCell.setAttribute('id', id) 140 | 141 | const clipboardButton = id => 142 | `` 145 | codeCell.insertAdjacentHTML('afterend', clipboardButton(id)) 146 | }) 147 | 148 | function escapeRegExp(string) { 149 | return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string 150 | } 151 | 152 | /** 153 | * Removes excluded text from a Node. 154 | * 155 | * @param {Node} target Node to filter. 156 | * @param {string} exclude CSS selector of nodes to exclude. 157 | * @returns {DOMString} Text from `target` with text removed. 158 | */ 159 | function filterText(target, exclude) { 160 | const clone = target.cloneNode(true); // clone as to not modify the live DOM 161 | if (exclude) { 162 | // remove excluded nodes 163 | clone.querySelectorAll(exclude).forEach(node => node.remove()); 164 | } 165 | return clone.innerText; 166 | } 167 | 168 | // Callback when a copy button is clicked. Will be passed the node that was clicked 169 | // should then grab the text and replace pieces of text that shouldn't be used in output 170 | function formatCopyText(textContent, copybuttonPromptText, isRegexp = false, onlyCopyPromptLines = true, removePrompts = true, copyEmptyLines = true, lineContinuationChar = "", hereDocDelim = "") { 171 | var regexp; 172 | var match; 173 | 174 | // Do we check for line continuation characters and "HERE-documents"? 175 | var useLineCont = !!lineContinuationChar 176 | var useHereDoc = !!hereDocDelim 177 | 178 | // create regexp to capture prompt and remaining line 179 | if (isRegexp) { 180 | regexp = new RegExp('^(' + copybuttonPromptText + ')(.*)') 181 | } else { 182 | regexp = new RegExp('^(' + escapeRegExp(copybuttonPromptText) + ')(.*)') 183 | } 184 | 185 | const outputLines = []; 186 | var promptFound = false; 187 | var gotLineCont = false; 188 | var gotHereDoc = false; 189 | const lineGotPrompt = []; 190 | for (const line of textContent.split('\n')) { 191 | match = line.match(regexp) 192 | if (match || gotLineCont || gotHereDoc) { 193 | promptFound = regexp.test(line) 194 | lineGotPrompt.push(promptFound) 195 | if (removePrompts && promptFound) { 196 | outputLines.push(match[2]) 197 | } else { 198 | outputLines.push(line) 199 | } 200 | gotLineCont = line.endsWith(lineContinuationChar) & useLineCont 201 | if (line.includes(hereDocDelim) & useHereDoc) 202 | gotHereDoc = !gotHereDoc 203 | } else if (!onlyCopyPromptLines) { 204 | outputLines.push(line) 205 | } else if (copyEmptyLines && line.trim() === '') { 206 | outputLines.push(line) 207 | } 208 | } 209 | 210 | // If no lines with the prompt were found then just use original lines 211 | if (lineGotPrompt.some(v => v === true)) { 212 | textContent = outputLines.join('\n'); 213 | } 214 | 215 | // Remove a trailing newline to avoid auto-running when pasting 216 | if (textContent.endsWith("\n")) { 217 | textContent = textContent.slice(0, -1) 218 | } 219 | return textContent 220 | } 221 | 222 | 223 | var copyTargetText = (trigger) => { 224 | var target = document.querySelector(trigger.attributes['data-clipboard-target'].value); 225 | 226 | // get filtered text 227 | let exclude = '.linenos'; 228 | 229 | let text = filterText(target, exclude); 230 | return formatCopyText(text, '>>> ', false, true, true, true, '', '') 231 | } 232 | 233 | // Initialize with a callback so we can modify the text before copy 234 | const clipboard = new ClipboardJS('.copybtn', {text: copyTargetText}) 235 | 236 | // Update UI with error/success messages 237 | clipboard.on('success', event => { 238 | clearSelection() 239 | temporarilyChangeTooltip(event.trigger, messages[locale]['copy'], messages[locale]['copy_success']) 240 | temporarilyChangeIcon(event.trigger) 241 | }) 242 | 243 | clipboard.on('error', event => { 244 | temporarilyChangeTooltip(event.trigger, messages[locale]['copy'], messages[locale]['copy_failure']) 245 | }) 246 | } 247 | 248 | runWhenDOMLoaded(addCopyButtonToCodeCells) 249 | -------------------------------------------------------------------------------- /docs/_build/_static/scripts/pydata-sphinx-theme.js: -------------------------------------------------------------------------------- 1 | (()=>{"use strict";function e(e){"loading"!=document.readyState?e():document.addEventListener("DOMContentLoaded",e)}const t=e=>"string"==typeof e&&/^[v\d]/.test(e)&&o.test(e),n=(e,t,n)=>{u(n);const o=((e,t)=>{const n=r(e),o=r(t),a=n.pop(),s=o.pop(),i=c(n,o);return 0!==i?i:a&&s?c(a.split("."),s.split(".")):a||s?a?-1:1:0})(e,t);return l[n].includes(o)},o=/^[v^~<>=]*?(\d+)(?:\.([x*]|\d+)(?:\.([x*]|\d+)(?:\.([x*]|\d+))?(?:-([\da-z\-]+(?:\.[\da-z\-]+)*))?(?:\+[\da-z\-]+(?:\.[\da-z\-]+)*)?)?)?$/i,r=e=>{if("string"!=typeof e)throw new TypeError("Invalid argument expected string");const t=e.match(o);if(!t)throw new Error(`Invalid argument not valid semver ('${e}' received)`);return t.shift(),t},a=e=>"*"===e||"x"===e||"X"===e,s=e=>{const t=parseInt(e,10);return isNaN(t)?e:t},i=(e,t)=>{if(a(e)||a(t))return 0;const[n,o]=((e,t)=>typeof e!=typeof t?[String(e),String(t)]:[e,t])(s(e),s(t));return n>o?1:n{for(let n=0;n":[1],">=":[0,1],"=":[0],"<=":[-1,0],"<":[-1]},d=Object.keys(l),u=e=>{if("string"!=typeof e)throw new TypeError("Invalid operator type, expected string but got "+typeof e);if(-1===d.indexOf(e))throw new Error(`Invalid operator, expected one of ${d.join("|")}`)};var m=window.matchMedia("(prefers-color-scheme: dark)");function h(e){document.documentElement.dataset.theme=m.matches?"dark":"light"}function p(e){"light"!==e&&"dark"!==e&&"auto"!==e&&(console.error(`Got invalid theme mode: ${e}. Resetting to auto.`),e="auto");var t=m.matches?"dark":"light";document.documentElement.dataset.mode=e;var n="auto"==e?t:e;document.documentElement.dataset.theme=n,document.querySelectorAll(".dropdown-menu").forEach((e=>{"dark"===n?e.classList.add("dropdown-menu-dark"):e.classList.remove("dropdown-menu-dark")})),localStorage.setItem("mode",e),localStorage.setItem("theme",n),console.log(`[PST]: Changed to ${e} mode using the ${n} theme.`),m.onchange="auto"==e?h:""}function f(){const e=document.documentElement.dataset.defaultMode||"auto",t=localStorage.getItem("mode")||e;var n,o;p(((o=(n=m.matches?["auto","light","dark"]:["auto","dark","light"]).indexOf(t)+1)===n.length&&(o=0),n[o]))}var g=()=>{let e=document.querySelectorAll("form.bd-search");return e.length?(1==e.length?e[0]:document.querySelector(":not(#pst-search-dialog) > form.bd-search")).querySelector("input"):void 0},v=()=>{const e=g(),t=document.getElementById("pst-search-dialog");e===t.querySelector("input")?t.open?t.close():t.showModal():document.activeElement===e?e.blur():(e.focus(),e.select(),e.scrollIntoView({block:"center"}))},y=0===navigator.platform.indexOf("Mac")||"iPhone"===navigator.platform;const w=({currentTarget:e,clientX:t,clientY:n})=>{if(!e.open)return;const{left:o,right:r,top:a,bottom:s}=e.getBoundingClientRect();(t"dirhtml"==DOCUMENTATION_OPTIONS.BUILDER?DOCUMENTATION_OPTIONS.pagename.endsWith("index")?`${DOCUMENTATION_OPTIONS.pagename.substring(0,DOCUMENTATION_OPTIONS.pagename.length-5)}`:`${DOCUMENTATION_OPTIONS.pagename}/`:`${DOCUMENTATION_OPTIONS.pagename}.html`;async function T(e){document.querySelector("#bd-header-version-warning").remove();const t=DOCUMENTATION_OPTIONS.VERSION,n=new Date,o=JSON.parse(localStorage.getItem("pst_banner_pref")||"{}");console.debug(`[PST] Dismissing the version warning banner on ${t} starting ${n}.`),o[t]=n,localStorage.setItem("pst_banner_pref",JSON.stringify(o))}async function S(e){e.preventDefault();const t=E();let n=e.currentTarget.getAttribute("href"),o=n.replace(t,"");try{(await fetch(n,{method:"HEAD"})).ok?location.href=n:location.href=o}catch(e){location.href=o}}async function b(){var e=document.querySelectorAll(".version-switcher__button");const o=e.length>0,r=DOCUMENTATION_OPTIONS.hasOwnProperty("theme_switcher_json_url"),a=DOCUMENTATION_OPTIONS.show_version_warning_banner;if(r&&(o||a)){const o=await async function(e){const t=E();try{var n=new URL(e)}catch(o){if(!(o instanceof TypeError))throw o;{"file:"==window.location.protocol&&console.info("[PST] looks like you're viewing this site from a local filesystem, so the version switcher won't work unless you've disabled CORS. See https://pydata-sphinx-theme.readthedocs.io/en/stable/user_guide/version-dropdown.html");const o=window.location.href.indexOf(t),r=-1==o?window.location.href:window.location.href.substring(0,o);n=new URL(e,r)}}const o=await fetch(n);return await o.json()}(DOCUMENTATION_OPTIONS.theme_switcher_json_url);o&&(function(e,t){const n=E();t.forEach((e=>{e.dataset.activeVersionName="",e.dataset.activeVersion=""}));const o=(e=e.map((e=>(e.match=e.version==DOCUMENTATION_OPTIONS.theme_switcher_version_match,e.preferred=e.preferred||!1,"name"in e||(e.name=e.version),e)))).map((e=>e.preferred&&e.match)).some(Boolean);var r=!1;e.forEach((e=>{const a=document.createElement("a");a.setAttribute("class","dropdown-item list-group-item list-group-item-action py-1"),a.setAttribute("href",`${e.url}${n}`),a.setAttribute("role","option");const s=document.createElement("span");s.textContent=`${e.name}`,a.appendChild(s),a.dataset.versionName=e.name,a.dataset.version=e.version;let i=o&&e.preferred,c=!o&&!r&&e.match;(i||c)&&(a.classList.add("active"),t.forEach((t=>{t.innerText=e.name,t.dataset.activeVersionName=e.name,t.dataset.activeVersion=e.version})),r=!0),document.querySelectorAll(".version-switcher__menu").forEach((e=>{let t=a.cloneNode(!0);t.onclick=S,e.append(t)}))}))}(o,e),a&&function(e){var o=DOCUMENTATION_OPTIONS.VERSION,r=e.filter((e=>e.preferred));if(1!==r.length){const e=0==r.length?"No":"Multiple";return void console.log(`[PST] ${e} versions marked "preferred" found in versions JSON, ignoring.`)}const a=r[0].version,s=r[0].url,i=t(o)&&t(a);if(i&&n(o,a,"="))return void console.log("[PST]: This is the preferred version of the docs, not showing the warning banner.");const c=JSON.parse(localStorage.getItem("pst_banner_pref")||"{}")[o];if(null!=c){const e=new Date(c),t=(new Date-e)/864e5;if(t<14)return void console.info(`[PST] Suppressing version warning banner; was dismissed ${Math.floor(t)} day(s) ago`)}const l=document.querySelector("#bd-header-version-warning"),d=document.createElement("div"),u=document.createElement("div"),m=document.createElement("strong"),h=document.createElement("a"),p=document.createElement("a");d.classList="bd-header-announcement__content ms-auto me-auto",u.classList="sidebar-message",h.classList="btn text-wrap font-weight-bold ms-3 my-1 align-baseline pst-button-link-to-stable-version",h.href=`${s}${E()}`,h.innerText="Switch to stable version",h.onclick=S,p.classList="ms-3 my-1 align-baseline";const f=document.createElement("i");p.append(f),f.classList="fa-solid fa-xmark",p.onclick=T,u.innerText="This is documentation for ";const g=o.includes("dev")||o.includes("rc")||o.includes("pre"),v=i&&n(o,a,">");g||v?m.innerText="an unstable development version":i&&n(o,a,"<")?m.innerText=`an old version (${o})`:m.innerText=o?`version ${o}`:"an unknown version",l.appendChild(d),l.append(p),d.appendChild(u),u.appendChild(m),u.appendChild(document.createTextNode(".")),u.appendChild(h),l.classList.remove("d-none")}(o))}}function O(){const e=()=>{document.querySelectorAll(["pre",".nboutput > .output_area",".cell_output > .output",".jp-RenderedHTMLCommon",".pst-scrollable-table-container"].join(", ")).forEach((e=>{e.tabIndex=e.scrollWidth>e.clientWidth||e.scrollHeight>e.clientHeight?0:-1}))},t=function(e,t){let n=null;return(...t)=>{clearTimeout(n),n=setTimeout((()=>{e(...t)}),300)}}(e);window.addEventListener("resize",t),new MutationObserver(t).observe(document.getElementById("main-content"),{subtree:!0,childList:!0}),e()}async function N(){const e=document.querySelector(".bd-header-announcement"),{pstAnnouncementUrl:t}=e?e.dataset:null;if(t)try{const n=await fetch(t);if(!n.ok)throw new Error(`[PST]: HTTP response status not ok: ${n.status} ${n.statusText}`);const o=await n.text();if(0===o.length)return void console.log(`[PST]: Empty announcement at: ${t}`);e.innerHTML=`
${o}
`,e.classList.remove("d-none")}catch(e){console.log(`[PST]: Failed to load announcement at: ${t}`),console.error(e)}}e((async function(){await Promise.allSettled([b(),N()]);const e=document.querySelector(".pst-async-banner-revealer");if(!e)return;e.classList.remove("d-none");const t=Array.from(e.children).reduce(((e,t)=>e+t.offsetHeight),0);e.style.setProperty("height",`${t}px`),setTimeout((()=>{e.style.setProperty("height","auto")}),320)})),e((function(){p(document.documentElement.dataset.mode),document.querySelectorAll(".theme-switch-button").forEach((e=>{e.addEventListener("click",f)}))})),e((function(){if(!document.querySelector(".bd-docs-nav"))return;var e=document.querySelector("div.bd-sidebar");let t=parseInt(sessionStorage.getItem("sidebar-scroll-top"),10);if(isNaN(t)){var n=document.querySelector(".bd-docs-nav").querySelectorAll(".active");if(n.length>0){var o=n[n.length-1],r=o.getBoundingClientRect().y-e.getBoundingClientRect().y;if(o.getBoundingClientRect().y>.5*window.innerHeight){let t=.25;e.scrollTop=r-e.clientHeight*t,console.log("[PST]: Scrolled sidebar using last active link...")}}}else e.scrollTop=t,console.log("[PST]: Scrolled sidebar using stored browser position...");window.addEventListener("beforeunload",(()=>{sessionStorage.setItem("sidebar-scroll-top",e.scrollTop)}))})),e((function(){window.addEventListener("activate.bs.scrollspy",(function(){document.querySelectorAll(".bd-toc-nav a").forEach((e=>{e.parentElement.classList.remove("active")})),document.querySelectorAll(".bd-toc-nav a.active").forEach((e=>{e.parentElement.classList.add("active")}))}))})),e((()=>{(()=>{let e=document.querySelectorAll(".search-button__kbd-shortcut");y&&e.forEach((e=>e.querySelector("kbd.kbd-shortcut__modifier").innerText="⌘"))})(),window.addEventListener("keydown",(e=>{let t=g();e.shiftKey||e.altKey||(y?!e.metaKey||e.ctrlKey:e.metaKey||!e.ctrlKey)||!/^k$/i.test(e.key)?document.activeElement===t&&/Escape/i.test(e.key)&&v():(e.preventDefault(),v())}),!0),document.querySelectorAll(".search-button__button").forEach((e=>{e.onclick=v})),document.getElementById("pst-search-dialog").addEventListener("click",w)})),e((function(){const e=document.getElementById("pst-primary-sidebar"),t=document.getElementById("pst-secondary-sidebar"),n=document.getElementById("pst-primary-sidebar-modal"),o=document.getElementById("pst-secondary-sidebar-modal"),r=document.querySelector(".primary-toggle"),a=document.querySelector(".secondary-toggle"),s=(e,t)=>{Array.from(e.childNodes).forEach((e=>t.appendChild(e))),Array.from(e.classList).forEach((n=>{e.classList.remove(n),t.classList.add(n)}))};[[r,n,e],[a,o,t]].forEach((([e,t,n])=>{e&&t&&n&&(e.addEventListener("click",(e=>{e.preventDefault(),e.stopPropagation(),s(n,t),t.showModal()})),t.addEventListener("click",w),t.addEventListener("keydown",(e=>{"Escape"===e.key&&(e.preventDefault(),e.stopPropagation(),t.close())})),t.addEventListener("close",(()=>{s(t,n)})))}))})),"complete"===document.readyState?O():window.addEventListener("load",O)})(); 2 | //# sourceMappingURL=pydata-sphinx-theme.js.map 3 | -------------------------------------------------------------------------------- /docs/_build/_modules/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Overview: module code — codalpy 0.4.0 documentation 11 | 12 | 13 | 14 | 18 | 21 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 |
63 | 64 | 66 | 67 | 68 | 69 | 70 | 85 | 86 | 87 |
88 | 89 |
90 | 91 | 92 | 180 | 181 | 182 |
183 |
184 | 185 | 186 | 187 | 188 | 189 | 190 |
191 | 192 | 193 | 194 | 232 | 233 | 234 | 243 | 244 | 245 |
246 | 247 |
248 | 249 | 250 |
251 |
252 | 253 |
254 |
255 | 256 |
257 | 258 |
259 | 260 | 271 |
272 | 273 |
274 | 275 | 276 |
277 |
278 | 279 | 280 | 281 | 282 | 283 |
284 | 285 |

All modules for which code is available

286 | 288 | 289 |
290 | 291 | 292 | 293 | 294 | 295 |
296 | 297 |
298 |
299 |
300 | 301 |
302 | 303 | 304 | 305 | 306 |
307 |
308 | 309 |
310 | 311 |
312 |
313 |
314 | 315 | 316 | 317 | 318 | 319 |
320 | 357 | 358 |
359 | 360 | 361 | -------------------------------------------------------------------------------- /docs/_build/search.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Search - codalpy 0.4.0 documentation 10 | 11 | 12 | 13 | 17 | 20 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 |
65 | 66 | 68 | 69 | 70 | 71 | 72 | 87 | 88 | 89 |
90 | 91 |
92 | 93 | 94 | 182 | 183 | 184 |
185 |
186 | 187 | 188 | 189 | 190 | 191 | 192 |
193 | 194 | 195 | 196 | 234 | 235 | 236 | 245 | 246 | 247 |
248 | 249 |
250 | 251 | 252 |
253 |
254 | 255 |
256 | 257 | 258 |
259 |

Search

260 | 266 | 267 | 282 |
283 |
284 | 293 | 294 | 295 | 296 | 297 | 298 |
299 | 300 |
301 |
302 |
303 | 304 |
305 | 306 | 307 | 308 | 309 |
310 |
311 | 312 |
313 | 314 |
315 |
316 |
317 | 318 | 319 | 320 | 321 | 322 |
323 | 360 | 361 |
362 | 363 | 364 | -------------------------------------------------------------------------------- /docs/_build/py-modindex.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Python Module Index — codalpy 0.4.0 documentation 11 | 12 | 13 | 14 | 18 | 21 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 |
66 | 67 | 69 | 70 | 71 | 72 | 73 | 88 | 89 | 90 |
91 | 92 |
93 | 94 | 95 | 183 | 184 | 185 |
186 |
187 | 188 | 189 | 190 | 191 | 192 | 193 |
194 | 195 | 196 | 197 | 235 | 236 | 237 | 246 | 247 | 248 |
249 | 250 |
251 | 252 | 253 |
254 |
255 | 256 |
257 | 258 | 259 | 260 | 261 | 262 |
263 | 264 | 265 |

Python Module Index

266 | 267 |
268 | c 269 |
270 | 271 | 272 | 273 | 275 | 276 | 278 | 281 | 282 | 283 | 286 | 287 | 288 | 291 |
 
274 | c
279 | codalpy 280 |
    284 | codalpy.codal 285 |
    289 | codalpy.models 290 |
292 | 293 | 294 |
295 | 296 | 297 | 298 | 299 | 300 |
301 | 302 |
303 |
304 |
305 | 306 |
307 | 308 | 309 | 310 | 311 |
312 |
313 | 314 |
315 | 316 |
317 |
318 |
319 | 320 | 321 | 322 | 323 | 324 |
325 | 362 | 363 |
364 | 365 | 366 | -------------------------------------------------------------------------------- /docs/_build/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | codalpy documentation — codalpy 0.4.0 documentation 12 | 13 | 14 | 15 | 19 | 22 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 |
65 | 66 | 68 | 69 | 70 | 71 | 72 | 87 | 88 | 89 |
90 | 91 |
92 | 93 | 94 | 186 | 187 | 188 |
189 |
190 | 191 | 192 | 193 | 194 | 195 | 196 |
197 | 198 | 199 | 200 | 238 | 239 | 240 | 249 | 250 | 251 |
252 | 253 |
254 | 255 | 256 |
257 |
258 | 259 |
260 | 261 | 262 | 263 | 264 | 265 |
266 | 267 |
268 |

codalpy documentation#

269 |

Add your content using reStructuredText syntax. See the 270 | reStructuredText 271 | documentation for details.

272 |
273 |

Contents:

274 | 280 |
281 |
282 | 283 | 284 |
285 | 286 | 287 | 288 | 289 | 290 | 304 | 305 |
306 | 307 | 308 | 309 | 310 |
323 | 324 | 325 |
326 |
327 | 328 |
329 | 330 |
331 |
332 |
333 | 334 | 335 | 336 | 337 | 338 |
339 | 376 | 377 |
378 | 379 | 380 | -------------------------------------------------------------------------------- /docs/_build/_static/alabaster.css: -------------------------------------------------------------------------------- 1 | /* -- page layout ----------------------------------------------------------- */ 2 | 3 | body { 4 | font-family: Georgia, serif; 5 | font-size: 17px; 6 | background-color: #fff; 7 | color: #000; 8 | margin: 0; 9 | padding: 0; 10 | } 11 | 12 | 13 | div.document { 14 | width: 940px; 15 | margin: 30px auto 0 auto; 16 | } 17 | 18 | div.documentwrapper { 19 | float: left; 20 | width: 100%; 21 | } 22 | 23 | div.bodywrapper { 24 | margin: 0 0 0 220px; 25 | } 26 | 27 | div.sphinxsidebar { 28 | width: 220px; 29 | font-size: 14px; 30 | line-height: 1.5; 31 | } 32 | 33 | hr { 34 | border: 1px solid #B1B4B6; 35 | } 36 | 37 | div.body { 38 | background-color: #fff; 39 | color: #3E4349; 40 | padding: 0 30px 0 30px; 41 | } 42 | 43 | div.body > .section { 44 | text-align: left; 45 | } 46 | 47 | div.footer { 48 | width: 940px; 49 | margin: 20px auto 30px auto; 50 | font-size: 14px; 51 | color: #888; 52 | text-align: right; 53 | } 54 | 55 | div.footer a { 56 | color: #888; 57 | } 58 | 59 | p.caption { 60 | font-family: inherit; 61 | font-size: inherit; 62 | } 63 | 64 | 65 | div.relations { 66 | display: none; 67 | } 68 | 69 | 70 | div.sphinxsidebar { 71 | max-height: 100%; 72 | overflow-y: auto; 73 | } 74 | 75 | div.sphinxsidebar a { 76 | color: #444; 77 | text-decoration: none; 78 | border-bottom: 1px dotted #999; 79 | } 80 | 81 | div.sphinxsidebar a:hover { 82 | border-bottom: 1px solid #999; 83 | } 84 | 85 | div.sphinxsidebarwrapper { 86 | padding: 18px 10px; 87 | } 88 | 89 | div.sphinxsidebarwrapper p.logo { 90 | padding: 0; 91 | margin: -10px 0 0 0px; 92 | text-align: center; 93 | } 94 | 95 | div.sphinxsidebarwrapper h1.logo { 96 | margin-top: -10px; 97 | text-align: center; 98 | margin-bottom: 5px; 99 | text-align: left; 100 | } 101 | 102 | div.sphinxsidebarwrapper h1.logo-name { 103 | margin-top: 0px; 104 | } 105 | 106 | div.sphinxsidebarwrapper p.blurb { 107 | margin-top: 0; 108 | font-style: normal; 109 | } 110 | 111 | div.sphinxsidebar h3, 112 | div.sphinxsidebar h4 { 113 | font-family: Georgia, serif; 114 | color: #444; 115 | font-size: 24px; 116 | font-weight: normal; 117 | margin: 0 0 5px 0; 118 | padding: 0; 119 | } 120 | 121 | div.sphinxsidebar h4 { 122 | font-size: 20px; 123 | } 124 | 125 | div.sphinxsidebar h3 a { 126 | color: #444; 127 | } 128 | 129 | div.sphinxsidebar p.logo a, 130 | div.sphinxsidebar h3 a, 131 | div.sphinxsidebar p.logo a:hover, 132 | div.sphinxsidebar h3 a:hover { 133 | border: none; 134 | } 135 | 136 | div.sphinxsidebar p { 137 | color: #555; 138 | margin: 10px 0; 139 | } 140 | 141 | div.sphinxsidebar ul { 142 | margin: 10px 0; 143 | padding: 0; 144 | color: #000; 145 | } 146 | 147 | div.sphinxsidebar ul li.toctree-l1 > a { 148 | font-size: 120%; 149 | } 150 | 151 | div.sphinxsidebar ul li.toctree-l2 > a { 152 | font-size: 110%; 153 | } 154 | 155 | div.sphinxsidebar input { 156 | border: 1px solid #CCC; 157 | font-family: Georgia, serif; 158 | font-size: 1em; 159 | } 160 | 161 | div.sphinxsidebar #searchbox { 162 | margin: 1em 0; 163 | } 164 | 165 | div.sphinxsidebar .search > div { 166 | display: table-cell; 167 | } 168 | 169 | div.sphinxsidebar hr { 170 | border: none; 171 | height: 1px; 172 | color: #AAA; 173 | background: #AAA; 174 | 175 | text-align: left; 176 | margin-left: 0; 177 | width: 50%; 178 | } 179 | 180 | div.sphinxsidebar .badge { 181 | border-bottom: none; 182 | } 183 | 184 | div.sphinxsidebar .badge:hover { 185 | border-bottom: none; 186 | } 187 | 188 | /* To address an issue with donation coming after search */ 189 | div.sphinxsidebar h3.donation { 190 | margin-top: 10px; 191 | } 192 | 193 | /* -- body styles ----------------------------------------------------------- */ 194 | 195 | a { 196 | color: #004B6B; 197 | text-decoration: underline; 198 | } 199 | 200 | a:hover { 201 | color: #6D4100; 202 | text-decoration: underline; 203 | } 204 | 205 | div.body h1, 206 | div.body h2, 207 | div.body h3, 208 | div.body h4, 209 | div.body h5, 210 | div.body h6 { 211 | font-family: Georgia, serif; 212 | font-weight: normal; 213 | margin: 30px 0px 10px 0px; 214 | padding: 0; 215 | } 216 | 217 | div.body h1 { margin-top: 0; padding-top: 0; font-size: 240%; } 218 | div.body h2 { font-size: 180%; } 219 | div.body h3 { font-size: 150%; } 220 | div.body h4 { font-size: 130%; } 221 | div.body h5 { font-size: 100%; } 222 | div.body h6 { font-size: 100%; } 223 | 224 | a.headerlink { 225 | color: #DDD; 226 | padding: 0 4px; 227 | text-decoration: none; 228 | } 229 | 230 | a.headerlink:hover { 231 | color: #444; 232 | background: #EAEAEA; 233 | } 234 | 235 | div.body p, div.body dd, div.body li { 236 | line-height: 1.4em; 237 | } 238 | 239 | div.admonition { 240 | margin: 20px 0px; 241 | padding: 10px 30px; 242 | background-color: #EEE; 243 | border: 1px solid #CCC; 244 | } 245 | 246 | div.admonition tt.xref, div.admonition code.xref, div.admonition a tt { 247 | background-color: #FBFBFB; 248 | border-bottom: 1px solid #fafafa; 249 | } 250 | 251 | div.admonition p.admonition-title { 252 | font-family: Georgia, serif; 253 | font-weight: normal; 254 | font-size: 24px; 255 | margin: 0 0 10px 0; 256 | padding: 0; 257 | line-height: 1; 258 | } 259 | 260 | div.admonition p.last { 261 | margin-bottom: 0; 262 | } 263 | 264 | dt:target, .highlight { 265 | background: #FAF3E8; 266 | } 267 | 268 | div.warning { 269 | background-color: #FCC; 270 | border: 1px solid #FAA; 271 | } 272 | 273 | div.danger { 274 | background-color: #FCC; 275 | border: 1px solid #FAA; 276 | -moz-box-shadow: 2px 2px 4px #D52C2C; 277 | -webkit-box-shadow: 2px 2px 4px #D52C2C; 278 | box-shadow: 2px 2px 4px #D52C2C; 279 | } 280 | 281 | div.error { 282 | background-color: #FCC; 283 | border: 1px solid #FAA; 284 | -moz-box-shadow: 2px 2px 4px #D52C2C; 285 | -webkit-box-shadow: 2px 2px 4px #D52C2C; 286 | box-shadow: 2px 2px 4px #D52C2C; 287 | } 288 | 289 | div.caution { 290 | background-color: #FCC; 291 | border: 1px solid #FAA; 292 | } 293 | 294 | div.attention { 295 | background-color: #FCC; 296 | border: 1px solid #FAA; 297 | } 298 | 299 | div.important { 300 | background-color: #EEE; 301 | border: 1px solid #CCC; 302 | } 303 | 304 | div.note { 305 | background-color: #EEE; 306 | border: 1px solid #CCC; 307 | } 308 | 309 | div.tip { 310 | background-color: #EEE; 311 | border: 1px solid #CCC; 312 | } 313 | 314 | div.hint { 315 | background-color: #EEE; 316 | border: 1px solid #CCC; 317 | } 318 | 319 | div.seealso { 320 | background-color: #EEE; 321 | border: 1px solid #CCC; 322 | } 323 | 324 | div.topic { 325 | background-color: #EEE; 326 | } 327 | 328 | p.admonition-title { 329 | display: inline; 330 | } 331 | 332 | p.admonition-title:after { 333 | content: ":"; 334 | } 335 | 336 | pre, tt, code { 337 | font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; 338 | font-size: 0.9em; 339 | } 340 | 341 | .hll { 342 | background-color: #FFC; 343 | margin: 0 -12px; 344 | padding: 0 12px; 345 | display: block; 346 | } 347 | 348 | img.screenshot { 349 | } 350 | 351 | tt.descname, tt.descclassname, code.descname, code.descclassname { 352 | font-size: 0.95em; 353 | } 354 | 355 | tt.descname, code.descname { 356 | padding-right: 0.08em; 357 | } 358 | 359 | img.screenshot { 360 | -moz-box-shadow: 2px 2px 4px #EEE; 361 | -webkit-box-shadow: 2px 2px 4px #EEE; 362 | box-shadow: 2px 2px 4px #EEE; 363 | } 364 | 365 | table.docutils { 366 | border: 1px solid #888; 367 | -moz-box-shadow: 2px 2px 4px #EEE; 368 | -webkit-box-shadow: 2px 2px 4px #EEE; 369 | box-shadow: 2px 2px 4px #EEE; 370 | } 371 | 372 | table.docutils td, table.docutils th { 373 | border: 1px solid #888; 374 | padding: 0.25em 0.7em; 375 | } 376 | 377 | table.field-list, table.footnote { 378 | border: none; 379 | -moz-box-shadow: none; 380 | -webkit-box-shadow: none; 381 | box-shadow: none; 382 | } 383 | 384 | table.footnote { 385 | margin: 15px 0; 386 | width: 100%; 387 | border: 1px solid #EEE; 388 | background: #FDFDFD; 389 | font-size: 0.9em; 390 | } 391 | 392 | table.footnote + table.footnote { 393 | margin-top: -15px; 394 | border-top: none; 395 | } 396 | 397 | table.field-list th { 398 | padding: 0 0.8em 0 0; 399 | } 400 | 401 | table.field-list td { 402 | padding: 0; 403 | } 404 | 405 | table.field-list p { 406 | margin-bottom: 0.8em; 407 | } 408 | 409 | /* Cloned from 410 | * https://github.com/sphinx-doc/sphinx/commit/ef60dbfce09286b20b7385333d63a60321784e68 411 | */ 412 | .field-name { 413 | -moz-hyphens: manual; 414 | -ms-hyphens: manual; 415 | -webkit-hyphens: manual; 416 | hyphens: manual; 417 | } 418 | 419 | table.footnote td.label { 420 | width: .1px; 421 | padding: 0.3em 0 0.3em 0.5em; 422 | } 423 | 424 | table.footnote td { 425 | padding: 0.3em 0.5em; 426 | } 427 | 428 | dl { 429 | margin-left: 0; 430 | margin-right: 0; 431 | margin-top: 0; 432 | padding: 0; 433 | } 434 | 435 | dl dd { 436 | margin-left: 30px; 437 | } 438 | 439 | blockquote { 440 | margin: 0 0 0 30px; 441 | padding: 0; 442 | } 443 | 444 | ul, ol { 445 | /* Matches the 30px from the narrow-screen "li > ul" selector below */ 446 | margin: 10px 0 10px 30px; 447 | padding: 0; 448 | } 449 | 450 | pre { 451 | background: unset; 452 | padding: 7px 30px; 453 | margin: 15px 0px; 454 | line-height: 1.3em; 455 | } 456 | 457 | div.viewcode-block:target { 458 | background: #ffd; 459 | } 460 | 461 | dl pre, blockquote pre, li pre { 462 | margin-left: 0; 463 | padding-left: 30px; 464 | } 465 | 466 | tt, code { 467 | background-color: #ecf0f3; 468 | color: #222; 469 | /* padding: 1px 2px; */ 470 | } 471 | 472 | tt.xref, code.xref, a tt { 473 | background-color: #FBFBFB; 474 | border-bottom: 1px solid #fff; 475 | } 476 | 477 | a.reference { 478 | text-decoration: none; 479 | border-bottom: 1px dotted #004B6B; 480 | } 481 | 482 | a.reference:hover { 483 | border-bottom: 1px solid #6D4100; 484 | } 485 | 486 | /* Don't put an underline on images */ 487 | a.image-reference, a.image-reference:hover { 488 | border-bottom: none; 489 | } 490 | 491 | a.footnote-reference { 492 | text-decoration: none; 493 | font-size: 0.7em; 494 | vertical-align: top; 495 | border-bottom: 1px dotted #004B6B; 496 | } 497 | 498 | a.footnote-reference:hover { 499 | border-bottom: 1px solid #6D4100; 500 | } 501 | 502 | a:hover tt, a:hover code { 503 | background: #EEE; 504 | } 505 | 506 | @media screen and (max-width: 940px) { 507 | 508 | body { 509 | margin: 0; 510 | padding: 20px 30px; 511 | } 512 | 513 | div.documentwrapper { 514 | float: none; 515 | background: #fff; 516 | margin-left: 0; 517 | margin-top: 0; 518 | margin-right: 0; 519 | margin-bottom: 0; 520 | } 521 | 522 | div.sphinxsidebar { 523 | display: block; 524 | float: none; 525 | width: unset; 526 | margin: 50px -30px -20px -30px; 527 | padding: 10px 20px; 528 | background: #333; 529 | color: #FFF; 530 | } 531 | 532 | div.sphinxsidebar h3, div.sphinxsidebar h4, div.sphinxsidebar p, 533 | div.sphinxsidebar h3 a { 534 | color: #fff; 535 | } 536 | 537 | div.sphinxsidebar a { 538 | color: #AAA; 539 | } 540 | 541 | div.sphinxsidebar p.logo { 542 | display: none; 543 | } 544 | 545 | div.document { 546 | width: 100%; 547 | margin: 0; 548 | } 549 | 550 | div.footer { 551 | display: none; 552 | } 553 | 554 | div.bodywrapper { 555 | margin: 0; 556 | } 557 | 558 | div.body { 559 | min-height: 0; 560 | min-width: auto; /* fixes width on small screens, breaks .hll */ 561 | padding: 0; 562 | } 563 | 564 | .hll { 565 | /* "fixes" the breakage */ 566 | width: max-content; 567 | } 568 | 569 | .rtd_doc_footer { 570 | display: none; 571 | } 572 | 573 | .document { 574 | width: auto; 575 | } 576 | 577 | .footer { 578 | width: auto; 579 | } 580 | 581 | .github { 582 | display: none; 583 | } 584 | 585 | ul { 586 | margin-left: 0; 587 | } 588 | 589 | li > ul { 590 | /* Matches the 30px from the "ul, ol" selector above */ 591 | margin-left: 30px; 592 | } 593 | } 594 | 595 | 596 | /* misc. */ 597 | 598 | .revsys-inline { 599 | display: none!important; 600 | } 601 | 602 | /* Hide ugly table cell borders in ..bibliography:: directive output */ 603 | table.docutils.citation, table.docutils.citation td, table.docutils.citation th { 604 | border: none; 605 | /* Below needed in some edge cases; if not applied, bottom shadows appear */ 606 | -moz-box-shadow: none; 607 | -webkit-box-shadow: none; 608 | box-shadow: none; 609 | } 610 | 611 | 612 | /* relbar */ 613 | 614 | .related { 615 | line-height: 30px; 616 | width: 100%; 617 | font-size: 0.9rem; 618 | } 619 | 620 | .related.top { 621 | border-bottom: 1px solid #EEE; 622 | margin-bottom: 20px; 623 | } 624 | 625 | .related.bottom { 626 | border-top: 1px solid #EEE; 627 | } 628 | 629 | .related ul { 630 | padding: 0; 631 | margin: 0; 632 | list-style: none; 633 | } 634 | 635 | .related li { 636 | display: inline; 637 | } 638 | 639 | nav#rellinks { 640 | float: right; 641 | } 642 | 643 | nav#rellinks li+li:before { 644 | content: "|"; 645 | } 646 | 647 | nav#breadcrumbs li+li:before { 648 | content: "\00BB"; 649 | } 650 | 651 | /* Hide certain items when printing */ 652 | @media print { 653 | div.related { 654 | display: none; 655 | } 656 | } 657 | 658 | img.github { 659 | position: absolute; 660 | top: 0; 661 | border: 0; 662 | right: 0; 663 | } 664 | -------------------------------------------------------------------------------- /docs/_build/autoapi/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | API Reference — codalpy 0.4.0 documentation 12 | 13 | 14 | 15 | 19 | 22 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 |
66 | 67 | 69 | 70 | 71 | 72 | 73 | 88 | 89 | 90 |
91 | 92 |
93 | 94 | 95 | 187 | 188 | 189 |
190 |
191 | 192 | 193 | 194 | 195 |
196 | 197 | 198 | 199 | 237 | 238 | 253 | 254 | 255 | 264 | 265 | 266 |
267 | 268 |
269 | 270 | 271 |
272 |
273 | 274 |
275 |
276 | 277 |
278 | 279 |
280 | 281 | 292 |
293 | 294 |
295 | 296 | 297 |
298 |
299 | 300 | 301 | 302 | 303 | 304 |
305 | 306 |
307 |

API Reference#

308 |

This page contains auto-generated API reference documentation [1].

309 |
310 | 317 |
318 | 324 |
325 | 326 | 327 |
328 | 329 | 330 | 331 | 332 | 333 | 356 | 357 |
358 | 359 | 360 | 361 | 362 |
375 | 376 | 377 |
378 |
379 | 380 |
381 | 382 |
383 |
384 |
385 | 386 | 387 | 388 | 389 | 390 |
391 | 428 | 429 |
430 | 431 | 432 | -------------------------------------------------------------------------------- /codalpy/codal.py: -------------------------------------------------------------------------------- 1 | import re 2 | from io import BytesIO 3 | from typing import Optional 4 | from urllib.parse import parse_qs, urlparse 5 | from tqdm import tqdm 6 | import polars as pl 7 | import requests 8 | 9 | from codalpy.utils.fund import clean_raw_portfolio_df, find_download_endpoint 10 | from codalpy.utils.http import HEADERS, get 11 | from codalpy.utils.issuer import Issuer, IssuerCategory, IssuerDType 12 | from codalpy.models import ( 13 | DataSource, 14 | DataSourceResult, 15 | GetDataSourceError, 16 | Letter, 17 | ) 18 | from codalpy.utils.query import Consts, QueryCategory, QueryLetterType, QueryParam 19 | from codalpy.utils.utils import normalize_fs_item 20 | 21 | 22 | class Codal: 23 | def __init__(self, issuer: str, from_jdate: str, to_jdate: str) -> None: 24 | self._issuer = Issuer().validate(issuer) 25 | self._query = QueryParam( 26 | symbol=self._issuer.alias, 27 | from_date=from_jdate, 28 | to_date=to_jdate, 29 | ) 30 | self._from_jdate = self._query.from_date 31 | self._to_jdate = self._query.to_date 32 | self._consts = Consts() 33 | 34 | @property 35 | def issuer(self): 36 | return self._issuer 37 | 38 | @issuer.setter 39 | def issuer(self, value: str): 40 | issuer_ = Issuer().validate(value) 41 | self._query = QueryParam.model_validate( 42 | {**self._query.model_dump(), "symbol": issuer_.alias} 43 | ) 44 | self._issuer = issuer_ 45 | 46 | @property 47 | def from_jdate(self): 48 | return self._from_jdate 49 | 50 | @from_jdate.setter 51 | def from_jdate(self, value: str): 52 | self._query = QueryParam.model_validate( 53 | {**self._query.model_dump(), "from_date": value} 54 | ) 55 | self._from_jdate = self._query.from_date 56 | 57 | @property 58 | def to_jdate(self): 59 | return self.to_jdate 60 | 61 | @to_jdate.setter 62 | def to_jdate(self, value: str): 63 | self._query = QueryParam.model_validate( 64 | {**self._query.model_dump(), "to_date": value} 65 | ) 66 | self._to_jdate = self._query.to_date 67 | 68 | @property 69 | def query(self): 70 | return self._query 71 | 72 | @query.setter 73 | def query(self, value: QueryParam): 74 | self._query = value 75 | 76 | @staticmethod 77 | def supported_issuers(cagegory: list[IssuerCategory]) -> list[IssuerDType]: 78 | """ 79 | .. raw:: html 80 | 81 |
82 | ناشرهایی که پشتیبانی میشه رو بهت میده. 83 |
84 | 85 | Parameters 86 | ---------- 87 | cagegory : list[IssuerCategory] 88 | The category of the issuer. 89 | 90 | Returns 91 | ------- 92 | list[IssuerDType] 93 | 94 | example 95 | ------- 96 | >>> from codalpy import Codal, IssuerCategory 97 | >>> Codal.supported_issuers([IssuerCategory.FUND])[:2] 98 | [IssuerDType(name='سهامی اهرمی کاریزما', symbol='اهرم', alias='اهرم', category=), 99 | IssuerDType(name='سهامی اهرمی مفید', symbol='توان', alias='توان', category=)] 100 | """ 101 | return Issuer().get_issuers_by_category(cagegory) 102 | 103 | def letter(self) -> list[Letter]: 104 | r = requests.get( 105 | url=self._consts.search_url, 106 | params=self._query.model_dump(by_alias=True, mode="json"), 107 | headers=HEADERS, 108 | ) 109 | data: dict = r.json() 110 | pages = str(data.get("Page")) 111 | Letter.base_url = self._consts.base_url 112 | letters = [Letter.model_validate(i) for i in data["Letters"]] 113 | if pages.isdigit(): 114 | pages = int(pages) 115 | if pages > 1: 116 | for p in range(2, pages + 1): 117 | self._query.page_number = p 118 | r = requests.get( 119 | url=self._consts.search_url, 120 | params=self._query.model_dump(by_alias=True, mode="json"), 121 | headers=HEADERS, 122 | ) 123 | data: dict = r.json() 124 | letters.extend([Letter.model_validate(i) for i in data["Letters"]]) 125 | return letters 126 | 127 | def _get_data_source( 128 | self, sheet_id: Optional[str] = None 129 | ) -> list[DataSourceResult]: 130 | letters = self.letter() 131 | records: list[DataSourceResult] = [] 132 | if letters is not None: 133 | pbar = tqdm(letters) 134 | for i in pbar: 135 | pbar.set_description(f"PJDate: {i.publish_date_time[:10]}") 136 | urlp = urlparse(i.url) 137 | params = parse_qs(urlp.query) 138 | if sheet_id is not None: 139 | params["SheetId"] = [sheet_id] 140 | r = get( 141 | url=f"{self._consts.base_url}{urlp.path}", 142 | params=params, 143 | rtype="text", 144 | ) 145 | data: DataSource | None = None 146 | error: GetDataSourceError | None = None 147 | status = "error" 148 | if r is not None: 149 | pattern = r"var datasource = (.*?);" 150 | match = re.search(pattern, r) 151 | if match: 152 | text = match.group(1) 153 | try: 154 | data = DataSource.model_validate_json(text) 155 | status = "success" 156 | except Exception as e: 157 | 158 | error = GetDataSourceError( 159 | source="validation", message=str(e) 160 | ) 161 | else: 162 | error = GetDataSourceError( 163 | source="match", message="Cannot find data." 164 | ) 165 | else: 166 | error = GetDataSourceError( 167 | source="match", message="Cannot find data." 168 | ) 169 | records.append( 170 | DataSourceResult(status=status, letter=i, data=data, error=error) 171 | ) 172 | return records 173 | 174 | def income_statement(self) -> list[DataSourceResult]: 175 | """ 176 | .. raw:: html 177 | 178 |
179 | داده هایٍ صورت-عملکردِ مالی رو بهت میده 180 |
181 | 182 | Returns 183 | ------- 184 | list[DataSourceResult] 185 | 186 | example 187 | ------- 188 | >>> from codalpy import Codal 189 | >>> codal = Codal( 190 | issuer = "شپدیس", 191 | from_jdate = "1401/01/01", 192 | to_jdate = "1404/12/29" 193 | ) 194 | >>> data = codal.income_statement() 195 | """ 196 | self._query.category = QueryCategory.ANNUAL_FINANCIAL_STATEMETNS 197 | self._query.letter_type = QueryLetterType.INTERIM_FINANCIAL_STATEMENTS 198 | data = self._get_data_source(sheet_id="1") 199 | return data 200 | 201 | def balance_sheet(self) -> list[DataSourceResult]: 202 | """ 203 | .. raw:: html 204 | 205 |
206 | داده هایٍ صورت-وضعیتِ مالی رو بهت میده 207 |
208 | 209 | Returns 210 | ------- 211 | list[DataSourceResult] 212 | 213 | example 214 | ------- 215 | >>> from codalpy import Codal 216 | >>> codal = Codal( 217 | issuer = "شپدیس", 218 | from_jdate = "1401/01/01", 219 | to_jdate = "1404/12/29" 220 | ) 221 | >>> data = codal.balance_sheet() 222 | """ 223 | self._query.category = QueryCategory.ANNUAL_FINANCIAL_STATEMETNS 224 | self._query.letter_type = QueryLetterType.INTERIM_FINANCIAL_STATEMENTS 225 | data = self._get_data_source(sheet_id="0") 226 | return data 227 | 228 | def monthly_activity(self) -> list[DataSourceResult]: 229 | """ 230 | .. raw:: html 231 | 232 |
233 | داده هایٍ فعالیتِ ماهانه رو بهت میده 234 |
235 | 236 | Returns 237 | ------- 238 | list[DataSourceResult] 239 | 240 | example 241 | ------- 242 | >>> from codalpy import Codal 243 | >>> codal = Codal( 244 | issuer = "شپدیس", 245 | from_jdate = "1404/04/01", 246 | to_jdate = "1404/12/29" 247 | ) 248 | >>> data = codal.monthly_activity() 249 | """ 250 | if self.issuer.category == IssuerCategory.FUND: 251 | raise ValueError("Issuer category should not be FUND") 252 | self._query.category = QueryCategory.MONTHLY_ACTIVITY 253 | self._query.letter_type = QueryLetterType.MONTHLY_ACTIVITY 254 | data = self._get_data_source() 255 | return data 256 | 257 | def fund_monthly_portfolio(self) -> pl.DataFrame: 258 | """ 259 | .. raw:: html 260 | 261 |
262 | پورتفوی سهامِ صندوق‌هایِ ETF رو به صورتِ‌ ماهانه بهت میده. 263 |
264 | 265 | Returns 266 | ------- 267 | polars.DataFrame 268 | 269 | example 270 | ------- 271 | >>> from codalpy import Codal 272 | >>> codal = Codal(issuer = "اهرم", from_jdate= "1404-04-04", to_jdate="1404-06-06") 273 | >>> codal.fund_monthly_portfolio() 274 | shape: (603, 18) 275 | ┌──────────────────────────────┬────────────┬────────────────┬──────────────────┬───┬────────┬─────────────────────────────────┬─────────────────────────────────┬─────────────────────────────────┐ 276 | │ name ┆ volume_beg ┆ total_cost_beg ┆ net_proceeds_beg ┆ … ┆ symbol ┆ title ┆ url ┆ attachment_url │ 277 | │ --- ┆ --- ┆ --- ┆ --- ┆ ┆ --- ┆ --- ┆ --- ┆ --- │ 278 | │ str ┆ i64 ┆ i64 ┆ i64 ┆ ┆ str ┆ str ┆ str ┆ str │ 279 | ╞══════════════════════════════╪════════════╪════════════════╪══════════════════╪═══╪════════╪═════════════════════════════════╪═════════════════════════════════╪═════════════════════════════════╡ 280 | │ آهن و فولاد غدیر ایرانیان ┆ 24500000 ┆ 140495106806 ┆ 123719463000 ┆ … ┆ اهرم ┆ صورت وضعیت پورتفوی صندوق سرمای… ┆ https://www.codal.ir/Reports/A… ┆ https://www.codal.ir/Reports/A… │ 281 | │ اقتصادی و خودکفایی آزادگان ┆ 58949663 ┆ 428681824109 ┆ 363313257531 ┆ … ┆ اهرم ┆ صورت وضعیت پورتفوی صندوق سرمای… ┆ https://www.codal.ir/Reports/A… ┆ https://www.codal.ir/Reports/A… │ 282 | │ البرزدارو ┆ 266248175 ┆ 853755414625 ┆ 982697425906 ┆ … ┆ اهرم ┆ صورت وضعیت پورتفوی صندوق سرمای… ┆ https://www.codal.ir/Reports/A… ┆ https://www.codal.ir/Reports/A… │ 283 | │ الحاوی ┆ 79400000 ┆ 175805992152 ┆ 102290130720 ┆ … ┆ اهرم ┆ صورت وضعیت پورتفوی صندوق سرمای… ┆ https://www.codal.ir/Reports/A… ┆ https://www.codal.ir/Reports/A… │ 284 | │ الکتریک‌ خودرو شرق‌ ┆ 117032944 ┆ 427355209792 ┆ 310735053213 ┆ … ┆ اهرم ┆ صورت وضعیت پورتفوی صندوق سرمای… ┆ https://www.codal.ir/Reports/A… ┆ https://www.codal.ir/Reports/A… │ 285 | │ … ┆ … ┆ … ┆ … ┆ … ┆ … ┆ … ┆ … ┆ … │ 286 | │ کشت و دامداری فکا ┆ 38000000 ┆ 42921313500 ┆ 137950282800 ┆ … ┆ اهرم ┆ صورت وضعیت پورتفوی صندوق سرمای… ┆ https://www.codal.ir/Reports/A… ┆ https://www.codal.ir/Reports/A… │ 287 | │ کویر تایر ┆ 84043466 ┆ 168768973101 ┆ 619056648665 ┆ … ┆ اهرم ┆ صورت وضعیت پورتفوی صندوق سرمای… ┆ https://www.codal.ir/Reports/A… ┆ https://www.codal.ir/Reports/A… │ 288 | │ ح . سرمایه گذاری‌البرز(هلدینگ‌ ┆ 0 ┆ 0 ┆ 0 ┆ … ┆ اهرم ┆ صورت وضعیت پورتفوی صندوق سرمای… ┆ https://www.codal.ir/Reports/A… ┆ https://www.codal.ir/Reports/A… │ 289 | │ سنگ آهن گهرزمین ┆ 0 ┆ 0 ┆ 0 ┆ … ┆ اهرم ┆ صورت وضعیت پورتفوی صندوق سرمای… ┆ https://www.codal.ir/Reports/A… ┆ https://www.codal.ir/Reports/A… │ 290 | │ ح . سنگ آهن گهرزمین ┆ 0 ┆ 0 ┆ 0 ┆ … ┆ اهرم ┆ صورت وضعیت پورتفوی صندوق سرمای… ┆ https://www.codal.ir/Reports/A… ┆ https://www.codal.ir/Reports/A… │ 291 | └──────────────────────────────┴────────────┴────────────────┴──────────────────┴───┴────────┴─────────────────────────────────┴─────────────────────────────────┴─────────────────────────────────┘ 292 | """ 293 | self._query.category = QueryCategory.MONTHLY_ACTIVITY 294 | self._query.letter_type = QueryLetterType.PORTFOLIO_POSITION 295 | letters = self.letter() 296 | df = pl.DataFrame() 297 | pbar = tqdm(letters) 298 | for letter in letters: 299 | pbar.set_description(f"PJDate: {letter.publish_date_time[:10]}") 300 | if letter.has_attachment: 301 | attachment = requests.get(letter.attachment_url, headers=HEADERS) 302 | xlsx_endpoint = find_download_endpoint(attachment.text) 303 | endpoint = "" 304 | if len(xlsx_endpoint) > 1: 305 | for i in xlsx_endpoint: 306 | if normalize_fs_item(self._issuer.symbol) in normalize_fs_item( 307 | i["description"] 308 | ): 309 | endpoint = i["link"] 310 | break 311 | elif len(xlsx_endpoint) == 1: 312 | endpoint = xlsx_endpoint[0]["link"] 313 | if endpoint: 314 | xlsx = requests.get( 315 | f"{self._consts.base_url}/Reports/{endpoint}", 316 | stream=True, 317 | headers=HEADERS, 318 | ) 319 | 320 | raw_df = pl.read_excel( 321 | BytesIO(xlsx.content), 322 | sheet_id=1, 323 | raise_if_empty=False, 324 | infer_schema_length=0, 325 | ) 326 | if raw_df.is_empty() or raw_df.shape[1] < 9: 327 | raw_df = pl.read_excel( 328 | BytesIO(xlsx.content), 329 | has_header=False, 330 | sheet_id=2, 331 | raise_if_empty=False, 332 | infer_schema_length=0, 333 | ) 334 | clean_df = clean_raw_portfolio_df(raw_df) 335 | clean_df = clean_df.with_columns( 336 | publish_date_time=pl.lit(letter.publish_date_time), 337 | issuer=pl.lit(self._issuer.symbol), 338 | title=pl.lit(letter.title), 339 | url=pl.lit(letter.url), 340 | attachment_url=pl.lit(letter.attachment_url), 341 | ) 342 | df = pl.concat([df, clean_df]) 343 | return df 344 | --------------------------------------------------------------------------------