settfex 0.22.2__tar.gz → 0.24.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {settfex-0.22.2 → settfex-0.24.0}/.github/workflows/dependency-drift.yml +24 -1
- {settfex-0.22.2 → settfex-0.24.0}/.github/workflows/release.yml +29 -4
- {settfex-0.22.2 → settfex-0.24.0}/AGENTS.md +106 -16
- {settfex-0.22.2 → settfex-0.24.0}/CHANGELOG.md +401 -0
- {settfex-0.22.2 → settfex-0.24.0}/CLAUDE.md +72 -2
- {settfex-0.22.2 → settfex-0.24.0}/PKG-INFO +22 -1
- {settfex-0.22.2 → settfex-0.24.0}/README.md +21 -0
- {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/services/sec/financial_report.md +82 -9
- {settfex-0.22.2 → settfex-0.24.0}/examples/sec/01_financial_report.ipynb +39 -8
- {settfex-0.22.2 → settfex-0.24.0}/pyproject.toml +1 -1
- {settfex-0.22.2 → settfex-0.24.0}/settfex/__init__.py +21 -1
- {settfex-0.22.2 → settfex-0.24.0}/settfex/exceptions.py +92 -3
- {settfex-0.22.2 → settfex-0.24.0}/settfex/services/sec/__init__.py +2 -0
- settfex-0.24.0/settfex/services/sec/company.py +211 -0
- {settfex-0.22.2 → settfex-0.24.0}/settfex/services/sec/download.py +99 -39
- {settfex-0.22.2 → settfex-0.24.0}/settfex/services/sec/financial_report.py +420 -68
- {settfex-0.22.2 → settfex-0.24.0}/settfex/services/sec/sec.py +27 -6
- {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/holiday.py +16 -1
- {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/index/info.py +4 -1
- {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/index/list.py +16 -4
- {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/stock/analyst_consensus.py +13 -11
- {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/stock/corporate_action.py +3 -3
- {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/stock/financial/financial.py +2 -2
- {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/stock/info.py +11 -2
- {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/stock/price_performance.py +4 -4
- {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/stock/trading_stat.py +3 -3
- {settfex-0.22.2 → settfex-0.24.0}/settfex/services/thaibma/availability.py +50 -1
- {settfex-0.22.2 → settfex-0.24.0}/settfex/services/thaibma/history.py +60 -3
- {settfex-0.22.2 → settfex-0.24.0}/settfex/utils/data_fetcher.py +17 -1
- {settfex-0.22.2 → settfex-0.24.0}/settfex/utils/parsing.py +45 -14
- {settfex-0.22.2 → settfex-0.24.0}/tests/golden/api_surface.json +378 -73
- settfex-0.24.0/tests/services/sec/test_code_isolation.py +281 -0
- settfex-0.24.0/tests/services/sec/test_company.py +346 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/sec/test_download_result.py +21 -5
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/sec/test_financial_report.py +34 -10
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/sec/test_financial_report_accounting.py +51 -1
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/sec/test_financial_report_th.py +2 -2
- settfex-0.24.0/tests/services/sec/test_sec.py +121 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/test_holiday.py +74 -5
- settfex-0.24.0/tests/services/test_fault_matrix.py +407 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/tfex/test_list.py +4 -2
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/tfex/test_trading_statistics.py +4 -2
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/tfex/test_underlying_price.py +7 -2
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/thaibma/test_availability.py +89 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/thaibma/test_history.py +121 -0
- settfex-0.24.0/tests/test_documented_exceptions.py +153 -0
- settfex-0.24.0/tests/test_readme_links.py +133 -0
- settfex-0.24.0/tests/test_typing_surface.py +135 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/utils/test_parsing.py +22 -7
- {settfex-0.22.2 → settfex-0.24.0}/uv.lock +1 -1
- settfex-0.22.2/settfex/services/sec/company.py +0 -96
- settfex-0.22.2/tests/services/sec/test_company.py +0 -80
- settfex-0.22.2/tests/services/sec/test_sec.py +0 -68
- {settfex-0.22.2 → settfex-0.24.0}/.editorconfig +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/.github/dependabot.yml +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/.github/instructions/core-architectrual-principles.instructions.md +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/.github/instructions/documentation-standards.instructions.md +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/.github/instructions/file-organization.instructions.md +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/.github/instructions/git-commit.instructions.md +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/.github/instructions/python-dependency-management.instructions.md +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/.github/prompts/Coding.prompt.md +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/.github/prompts/Git-Commit-Reviewer.prompt.md +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/.github/prompts/Prompt-Engineer.prompt.md +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/.github/prompts/Python-Architect.prompt.md +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/.github/workflows/ci.yml +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/.github/workflows/pre-commit.yml +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/.github/workflows/security.yml +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/.gitignore +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/.pre-commit-config.yaml +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/.python-version +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/CODE_OF_CONDUCT.md +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/COMPREHENSIVE_AUDIT.md +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/CONTRIBUTING.md +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/LICENSE +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/RELEASING.md +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/SECURITY.md +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/docs/guide/PYTHON_LIBRARY_BEST_PRACTICES.md +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/docs/index.md +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/services/set/API_PROTECTION_NOTE.md +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/services/set/analyst_consensus.md +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/services/set/board_of_director.md +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/services/set/chart_quotation.md +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/services/set/corporate_action.md +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/services/set/dr_indicative_price.md +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/services/set/earnings_call.md +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/services/set/financial.md +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/services/set/highlight_data.md +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/services/set/holiday.md +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/services/set/index.md +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/services/set/info.md +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/services/set/latest_historical_trading.md +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/services/set/list.md +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/services/set/news.md +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/services/set/nvdr_holder.md +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/services/set/price_performance.md +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/services/set/profile_company.md +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/services/set/profile_dr.md +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/services/set/profile_stock.md +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/services/set/shareholder.md +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/services/set/trading_stat.md +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/services/tfex/list.md +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/services/tfex/trading_statistics.md +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/services/thaibma/yield_curve.md +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/utils/data_fetcher.md +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/utils/session_caching.md +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/docs/solution/FINDINGS.md +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/docs/solution/Performance Boost Session Caching Implementation.md +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/docs/solution/SESSION_CACHE_SUMMARY.md +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/docs/solution/SOLUTION_100_PERCENT.md +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/examples/README.md +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/examples/set/01_stock_list.ipynb +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/examples/set/02_highlight_data.ipynb +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/examples/set/03_stock_profile.ipynb +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/examples/set/04_company_profile.ipynb +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/examples/set/05_corporate_action.ipynb +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/examples/set/06_shareholder.ipynb +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/examples/set/07_nvdr_holder.ipynb +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/examples/set/08_board_of_director.ipynb +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/examples/set/09_trading_statistics.ipynb +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/examples/set/10_price_performance.ipynb +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/examples/set/11_financial.ipynb +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/examples/set/12_earnings_call.ipynb +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/examples/set/13_chart_quotation.ipynb +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/examples/set/14_latest_historical_trading.ipynb +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/examples/set/15_market_index.ipynb +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/examples/set/16_news.ipynb +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/examples/set/17_holiday.ipynb +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/examples/set/18_dr_and_asset_type.ipynb +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/examples/set/19_analyst_consensus.ipynb +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/examples/set/20_stock_info.ipynb +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/examples/set/README.md +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/examples/set/cpall_balance_sheet.csv +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/examples/set/market_dashboard_20251005_173221.csv +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/examples/set/market_dashboard_20251005_210737.csv +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/examples/set/market_dashboard_20251006_091440.csv +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/examples/set/thailand_banking_stocks.csv +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/examples/set/thailand_set_main_board.csv +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/examples/set/thailand_stock_universe.csv +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/examples/tfex/01_series_list.ipynb +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/examples/tfex/02_trading_statistics.ipynb +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/examples/tfex/03_underlying_price.ipynb +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/examples/thaibma/01_government_yield_curve.ipynb +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/settfex/py.typed +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/settfex/services/__init__.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/settfex/services/sec/constants.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/settfex/services/sec/utils.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/__init__.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/asset_type.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/constants.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/earnings_call.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/index/__init__.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/index/chart_quotation.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/index/composition.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/index/index.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/index/utils.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/list.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/news.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/stock/__init__.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/stock/board_of_director.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/stock/chart_quotation.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/stock/dr_indicative_price.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/stock/financial/__init__.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/stock/highlight_data.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/stock/latest_historical_trading.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/stock/nvdr_holder.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/stock/profile_company.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/stock/profile_dr.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/stock/profile_stock.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/stock/shareholder.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/stock/stock.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/stock/utils.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/settfex/services/tfex/__init__.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/settfex/services/tfex/constants.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/settfex/services/tfex/list.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/settfex/services/tfex/trading_statistics.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/settfex/services/tfex/underlying_price.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/settfex/services/thaibma/__init__.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/settfex/services/thaibma/constants.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/settfex/services/thaibma/thaibma.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/settfex/services/thaibma/utils.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/settfex/services/thaibma/yield_curve.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/settfex/utils/__init__.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/settfex/utils/http.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/settfex/utils/logging.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/settfex/utils/session_cache.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/settfex/utils/session_manager.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/settfex/utils/youtube_transcript.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/__init__.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/conftest.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/golden/model_contract/analyst_consensus.json +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/golden/model_contract/dr_profile.json +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/golden/model_contract/earnings_call_item.json +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/golden/model_contract/highlight_data.json +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/golden/model_contract/holiday_calendar.json +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/golden/model_contract/index_list_response.json +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/golden/model_contract/news_search_response.json +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/golden/model_contract/sec_company_match.json +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/golden/model_contract/stock_info.json +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/golden/model_contract/stock_list_response.json +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/golden/model_contract/tfex_series_list_response.json +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/golden/model_contract/tfex_trading_statistics.json +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/golden/model_contract/tfex_underlying_price.json +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/golden/model_contract/yield_curve.json +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/integration/__init__.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/integration/test_live_endpoints.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/__init__.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/sec/__init__.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/sec/derive_th_fixtures.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/sec/fixtures.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/sec/fixtures_sec/README.md +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/sec/fixtures_sec/capital_indirection_en.html +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/sec/fixtures_sec/en_mother_fs_h1_2025.html +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/sec/fixtures_sec/en_ptt_56_1.html +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/sec/fixtures_sec/en_ptt_56_2.html +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/sec/fixtures_sec/en_ptt_fs_h1_2025.html +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/sec/fixtures_sec/en_ptt_viewmore_56_2.html +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/sec/fixtures_sec/idisc_505_error_page.html +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/sec/fixtures_sec/th_cpall_viewmore_56_1.html +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/sec/fixtures_sec/th_mother_fs_h1_2025.html +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/sec/fixtures_sec/th_ptt_56_1.html +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/sec/fixtures_sec/th_ptt_56_2.html +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/sec/fixtures_sec/th_ptt_fs_h1_2025.html +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/sec/test_download.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/sec/test_download_indirection.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/sec/test_listing_transport.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/sec/test_utils.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/sec/test_view_more_slugs.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/__init__.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/index/__init__.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/index/test_chart_quotation.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/index/test_composition.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/index/test_index.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/index/test_info.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/index/test_list.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/stock/__init__.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/stock/financial/__init__.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/stock/financial/test_financial.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/stock/test_analyst_consensus.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/stock/test_chart_quotation.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/stock/test_dr_indicative_price.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/stock/test_info.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/stock/test_latest_historical_trading.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/stock/test_profile_dr.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/test_asset_type.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/test_board_of_director.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/test_client.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/test_corporate_action.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/test_earnings_call.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/test_historical.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/test_list.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/test_news.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/test_profile_company.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/test_realtime.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/test_shareholder.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/test_symbol_suggestion.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/tfex/__init__.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/tfex/test_client.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/tfex/test_historical.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/tfex/test_realtime.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/thaibma/__init__.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/thaibma/fixtures.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/thaibma/test_thaibma.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/thaibma/test_utils.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/services/thaibma/test_yield_curve.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/test_impersonate_target.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/test_model_contract.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/test_public_api_surface.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/utils/__init__.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/utils/test_data_fetcher.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/utils/test_formatting.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/utils/test_http.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/utils/test_logging.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/utils/test_session_cache.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/utils/test_session_manager.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/utils/test_validation.py +0 -0
- {settfex-0.22.2 → settfex-0.24.0}/tests/utils/test_youtube_transcript.py +0 -0
|
@@ -21,6 +21,17 @@ permissions:
|
|
|
21
21
|
contents: read
|
|
22
22
|
issues: write
|
|
23
23
|
|
|
24
|
+
# Serialise runs. This does NOT stop a double *refresh* -- the two runs on 2026-09-19 were separate
|
|
25
|
+
# manual dispatches 20 minutes apart, each lasting ~16 s, so they never overlapped and a group would
|
|
26
|
+
# have changed nothing. What it does guard is the read-modify-write below: two OVERLAPPING runs
|
|
27
|
+
# could both find no open issue, both pass the `-z "$NUMBER"` check, and CREATE TWO standing issues
|
|
28
|
+
# -- which then permanently breaks the "exactly one" invariant this workflow depends on.
|
|
29
|
+
# `cancel-in-progress: false` on purpose: cancelling mid-write could leave the issue body replaced
|
|
30
|
+
# and its comment missing.
|
|
31
|
+
concurrency:
|
|
32
|
+
group: dependency-drift
|
|
33
|
+
cancel-in-progress: false
|
|
34
|
+
|
|
24
35
|
jobs:
|
|
25
36
|
report:
|
|
26
37
|
name: Outdated report
|
|
@@ -157,5 +168,17 @@ jobs:
|
|
|
157
168
|
--body-file body.md
|
|
158
169
|
else
|
|
159
170
|
gh issue edit "$NUMBER" --body-file body.md
|
|
160
|
-
|
|
171
|
+
# Comment at most ONCE per day. The body edit above is idempotent -- it is replaced
|
|
172
|
+
# wholesale and carries its own date header -- but the comment is append-only, so a
|
|
173
|
+
# second dispatch on the same day left #109 with two identical "Refreshed" comments
|
|
174
|
+
# (observed 2026-09-19, 20 minutes apart). The comment exists to raise a notification,
|
|
175
|
+
# and a second notification for an unchanged report is noise.
|
|
176
|
+
TODAY=$(date -u +%F)
|
|
177
|
+
ALREADY=$(gh issue view "$NUMBER" --json comments \
|
|
178
|
+
--jq "[.comments[] | select(.body | contains(\"Refreshed ${TODAY}\"))] | length")
|
|
179
|
+
if [ "${ALREADY:-0}" -eq 0 ]; then
|
|
180
|
+
gh issue comment "$NUMBER" --body "Refreshed ${TODAY} by the dependency-drift workflow."
|
|
181
|
+
else
|
|
182
|
+
echo "Already refreshed today (${ALREADY} comment(s)); body updated, comment skipped."
|
|
183
|
+
fi
|
|
161
184
|
fi
|
|
@@ -12,6 +12,11 @@ on:
|
|
|
12
12
|
tags:
|
|
13
13
|
- 'v[0-9]+.[0-9]+.[0-9]+'
|
|
14
14
|
- 'v[0-9]+.[0-9]+.[0-9]+-*'
|
|
15
|
+
# PEP 440 spells a pre-release with NO hyphen (0.24.0rc1); SemVer uses one (0.24.0-rc1).
|
|
16
|
+
# The tag mirrors the pyproject version, which must be PEP 440, so both spellings are
|
|
17
|
+
# accepted. Without this line `v0.24.0rc1` matched neither pattern and the workflow simply
|
|
18
|
+
# never ran -- a tag push that looks successful and publishes nothing.
|
|
19
|
+
- 'v[0-9]+.[0-9]+.[0-9]+[a-z]+[0-9]+'
|
|
15
20
|
|
|
16
21
|
permissions:
|
|
17
22
|
contents: write # create GitHub Release + upload assets
|
|
@@ -36,7 +41,10 @@ jobs:
|
|
|
36
41
|
VERSION="${TAG#v}"
|
|
37
42
|
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
|
|
38
43
|
|
|
39
|
-
|
|
44
|
+
# The hyphen is OPTIONAL: PEP 440 writes `0.24.0rc1`, so requiring `-rc` would have
|
|
45
|
+
# classified the first PEP 440 pre-release this repo ever tagged as a FULL release and
|
|
46
|
+
# marked it "Latest" on GitHub -- the opposite of the intent.
|
|
47
|
+
if [[ "$TAG" =~ -?(alpha|beta|rc)[0-9]*$ ]]; then
|
|
40
48
|
echo "is_prerelease=true" >> "$GITHUB_OUTPUT"
|
|
41
49
|
else
|
|
42
50
|
echo "is_prerelease=false" >> "$GITHUB_OUTPUT"
|
|
@@ -177,9 +185,26 @@ jobs:
|
|
|
177
185
|
import re, sys
|
|
178
186
|
version = sys.argv[1]
|
|
179
187
|
content = open("CHANGELOG.md").read()
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
188
|
+
|
|
189
|
+
def section(heading: str) -> str | None:
|
|
190
|
+
pattern = rf"(?m)^## \[{re.escape(heading)}\][^\n]*\n(.*?)(?=^## \[|\Z)"
|
|
191
|
+
found = re.search(pattern, content, re.DOTALL)
|
|
192
|
+
return found.group(1).strip() if found else None
|
|
193
|
+
|
|
194
|
+
# A pre-release documents the version it is a candidate FOR: `0.24.0rc1` is described by
|
|
195
|
+
# the `## [0.24.0]` section, and duplicating that section under an rc heading would mean
|
|
196
|
+
# maintaining two copies of the same notes. So fall back to the base version.
|
|
197
|
+
# Without this the body silently became the stub "Release v0.24.0rc1" -- a release that
|
|
198
|
+
# looks fine and carries none of its own notes.
|
|
199
|
+
base = re.match(r"^(\d+\.\d+\.\d+)", version)
|
|
200
|
+
notes = section(version)
|
|
201
|
+
if notes is None and base is not None and base.group(1) != version:
|
|
202
|
+
notes = section(base.group(1))
|
|
203
|
+
if notes is not None:
|
|
204
|
+
notes = f"> Pre-release of **{base.group(1)}**.\n\n{notes}"
|
|
205
|
+
if notes is None:
|
|
206
|
+
print(f"::error::No CHANGELOG section for {version} or its base version")
|
|
207
|
+
sys.exit(1)
|
|
183
208
|
with open("release_notes.txt", "w") as f:
|
|
184
209
|
f.write(notes + "\n")
|
|
185
210
|
PYEOF
|
|
@@ -107,12 +107,37 @@ Indices: `get_index_list(lang)`, `get_index_info(symbol, lang)`,
|
|
|
107
107
|
|
|
108
108
|
| I want… | Call |
|
|
109
109
|
|---|---|
|
|
110
|
-
| resolve a company to its SEC id | `resolve_company(query, lang)` |
|
|
110
|
+
| resolve a company to its SEC id | `resolve_company(query, lang, allow_name_match=False)` |
|
|
111
111
|
| list filings (financial statements, 56-1, 56-2, ratios, MD&A) | `get_sec_documents(query, types=..., from_date=..., to_date=...)` |
|
|
112
112
|
| download the actual file(s) | `download_sec_document(target)` / `download_sec_documents(targets)` |
|
|
113
113
|
|
|
114
114
|
Dates here are **dd/mm/yyyy**. Pass a wide window to see full year history.
|
|
115
115
|
|
|
116
|
+
⚠️ **Not every SET symbol is an SEC issuer.** ETFs, warrants, DWs and `-F` foreign lines do not
|
|
117
|
+
file, so resolving one of them raises rather than guessing (0.24.0):
|
|
118
|
+
|
|
119
|
+
| outcome | exception | what to do |
|
|
120
|
+
|---|---|---|
|
|
121
|
+
| nothing matched | `CompanyNotFoundError` | report that no issuer exists; do not retry |
|
|
122
|
+
| several matched, none flagged | `AmbiguousCompanyError` | read `exc.candidates` (each a `CompanyMatch`) and ask which one, or pass an exact symbol |
|
|
123
|
+
| **exactly one matched, not flagged** | `AmbiguousCompanyError` | the site did not recognise your query as an *identifier*, so that row is a substring hit on a company **name**. If you meant a name, pass `allow_name_match=True`; if you meant a symbol, it is not an SEC issuer |
|
|
124
|
+
|
|
125
|
+
**Searching by company name?** Pass `allow_name_match=True` — a name never flags, so a name lookup
|
|
126
|
+
always lands in that third row:
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
await get_sec_documents("CP ALL PUBLIC COMPANY LIMITED", allow_name_match=True)
|
|
130
|
+
await resolve_company("ปตท", allow_name_match=True) # still raises: 17 candidates, none flagged
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
It only ever affects the **single**-candidate case. Several unflagged candidates stay ambiguous
|
|
134
|
+
whatever you intended.
|
|
135
|
+
|
|
136
|
+
Both are **`ValueError`s, not `FetchError`s**, because the request succeeded — retrying returns the
|
|
137
|
+
same answer forever, so `except FetchError: retry` must not be what catches them. Before 0.24.0 the
|
|
138
|
+
second case returned an arbitrary alphabetically-first company: `CHINA` (an ETF) resolved to
|
|
139
|
+
`ASEAN CHINA INVESTMENT FUND L.P.` and every filing listed under it was the wrong company's.
|
|
140
|
+
|
|
116
141
|
`lang="th"` works and returns the **Thai-language filing documents** — different files from the
|
|
117
142
|
English ones, not a translated index. Years and dates come back as **C.E.** in the model even
|
|
118
143
|
though the Thai page states them in the Buddhist era (`2568` → `2025`). Free-text cells
|
|
@@ -130,16 +155,35 @@ listing where **every** usable row was lost raises `IncompleteListingError` rath
|
|
|
130
155
|
transport: a failed request raises `FetchError`, and a body that is not a listing page raises
|
|
131
156
|
`ParseError`, instead of parsing to zero rows and looking like "this issuer filed nothing".
|
|
132
157
|
|
|
133
|
-
|
|
134
|
-
its truncated inline rows and the shortfall shows in `completeness()
|
|
135
|
-
|
|
136
|
-
|
|
158
|
+
Two things deliberately do **not** raise. A broken "display all results" page: that section keeps
|
|
159
|
+
its truncated inline rows and the shortfall shows in `completeness()`. And **one failing report
|
|
160
|
+
code**: the others keep their documents, and the failure is recorded on
|
|
161
|
+
`docs.accounting.failed_codes` (with a WARNING). So after a call that returned normally, check
|
|
162
|
+
`docs.accounting.has_losses` before treating the result as complete — an exception is no longer how
|
|
163
|
+
a partial failure announces itself. `repr(docs)` states it too.
|
|
164
|
+
|
|
165
|
+
As of 2026-09-20 SEC's Thai `fs-kf` page answers HTTP 500, which is an upstream bug, not a settfex
|
|
166
|
+
one; it shows up as a `key_financial_ratio` shortfall on Thai listings.
|
|
167
|
+
|
|
168
|
+
As of 0.24.0 `SecDocumentList` is a **Pydantic model** `{documents, accounting, reported_counts}`
|
|
169
|
+
that still iterates, indexes and slices like the list it used to be — and a **slice keeps the
|
|
170
|
+
accounting** (of the whole call, not of the slice). So `model_dump()` and JSON carry the
|
|
171
|
+
completeness signal, which matters here more than anywhere: what you receive from a tool call is
|
|
172
|
+
JSON, so a signal that does not serialize does not reach you at all.
|
|
173
|
+
|
|
174
|
+
⚠️ `isinstance(docs, list)` is now `False` — it fails *silently*, by taking the other branch. Use
|
|
175
|
+
`docs.documents` where a real list is needed. `sorted(docs)` and `list(docs)` still give plain
|
|
176
|
+
lists, so sort `docs.documents`.
|
|
177
|
+
|
|
178
|
+
⚠️ A section whose "display all results" page failed lands on `accounting.degraded_sections` and
|
|
179
|
+
sets `has_losses` — that is how the live Thai `fs-kf` HTTP 500 above surfaces.
|
|
137
180
|
|
|
138
181
|
`download_sec_documents(...)` returns a `DownloadResult` — a list of the files that downloaded,
|
|
139
182
|
which also carries `.failed` (each with its target and reason) and `.is_complete`. Check it before
|
|
140
183
|
reporting a batch as done; dead links on the SEC host arrive as HTML under HTTP 200, not as errors.
|
|
141
|
-
|
|
142
|
-
|
|
184
|
+
Also a Pydantic model since 0.24.0 (`{files, failed, requested}` + computed `is_complete`), so the
|
|
185
|
+
failure report survives `model_dump()` and slicing. ⚠️ `isinstance(files, list)` is `False`; use
|
|
186
|
+
`files.files`.
|
|
143
187
|
|
|
144
188
|
### ThaiBMA bonds — `from settfex.services.thaibma import ...`
|
|
145
189
|
|
|
@@ -225,23 +269,62 @@ being wrong, so none of them will announce itself.
|
|
|
225
269
|
|
|
226
270
|
## Errors you should expect
|
|
227
271
|
|
|
272
|
+
Everything is importable from one place:
|
|
273
|
+
|
|
228
274
|
```python
|
|
229
275
|
from settfex.exceptions import (
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
276
|
+
# --- the FETCH family: `except FetchError` catches all of these ---
|
|
277
|
+
FetchError, # HTTP/transport failure; carries .status_code and .symbol
|
|
278
|
+
HTTPStatusError, # a non-2xx, with .url and .report_code as data
|
|
279
|
+
SymbolNotFoundError, # HTTP 404 on a SET endpoint; may carry .suggestion
|
|
280
|
+
StaleDataError, # ThaiBMA rolled back and you asked it to raise
|
|
281
|
+
ParseError, # a response arrived intact and could not be mapped
|
|
282
|
+
IncompleteListingError, # a ParseError: rows classified, then every one was lost
|
|
283
|
+
# --- INPUT errors: ValueErrors, NOT caught by `except FetchError` ---
|
|
284
|
+
CompanyNotFoundError, # SEC: the search ran and matched no issuer
|
|
285
|
+
AmbiguousCompanyError, # SEC: several matched, none flagged; carries .candidates
|
|
286
|
+
InvalidSymbolError, # empty symbol — raised before any request
|
|
287
|
+
InvalidLanguageError, # unrecognized lang
|
|
288
|
+
InvalidDateError, # malformed date string — raised before any request
|
|
236
289
|
)
|
|
237
|
-
from settfex.utils.parsing import ResponseParseError
|
|
290
|
+
from settfex.utils.parsing import ResponseParseError # also a ParseError since 0.24.0
|
|
238
291
|
```
|
|
239
292
|
|
|
240
|
-
|
|
241
|
-
|
|
293
|
+
**The split is the thing to internalise: a `FetchError` may be worth retrying; a `ValueError`
|
|
294
|
+
never is.** An input error means the request *succeeded* and your argument was wrong, so a retry
|
|
295
|
+
loop on one spins forever. `InvalidSymbolError`, `InvalidLanguageError` and `InvalidDateError` are
|
|
296
|
+
raised before any network call at all.
|
|
297
|
+
|
|
298
|
+
⚠️ Two "not found" taxonomies coexist today: a SET 404 is a `SymbolNotFoundError` (a `FetchError`),
|
|
299
|
+
while the SEC equivalent is a `CompanyNotFoundError` (a `ValueError`). Catch both if you handle
|
|
300
|
+
both hosts. Unifying them is tracked on #135.
|
|
301
|
+
|
|
302
|
+
⚠️ `ResponseParseError` is also what a **WAF block page** currently surfaces as — right family,
|
|
303
|
+
wrong diagnosis. If you see it repeatedly from one host, **stop and back off**; do not retry.
|
|
242
304
|
|
|
243
305
|
---
|
|
244
306
|
|
|
307
|
+
## Timed instructions
|
|
308
|
+
|
|
309
|
+
If you are told to do something at a particular time, that instruction needs **a date, a clock time
|
|
310
|
+
and a timezone** — `2026-09-21 17:00 ICT`. Relative words (*today*, *tonight*, *after close*) are
|
|
311
|
+
ambiguous the moment a conversation spans midnight or is resumed later, and they give no signal
|
|
312
|
+
that they have gone stale.
|
|
313
|
+
|
|
314
|
+
**Check the current time before acting on one.** If the window has passed, say so and ask rather
|
|
315
|
+
than substituting the nearest equivalent — the reason a window was chosen (avoiding market hours,
|
|
316
|
+
avoiding another system's traffic) usually does not survive being moved by a day.
|
|
317
|
+
|
|
318
|
+
## Communication language
|
|
319
|
+
|
|
320
|
+
- All prose you write is in English: reports and chat replies to the operator, commit messages,
|
|
321
|
+
PR descriptions, GitHub issues and comments, docs, ADRs, and code comments.
|
|
322
|
+
- Thai appears only as verbatim source data: document titles, labels (e.g. `สอบทาน`), company
|
|
323
|
+
names, URLs, quoted page text, and fixture contents. Keep it exactly as the source has it —
|
|
324
|
+
never translate or transliterate the data itself.
|
|
325
|
+
- When a Thai value's meaning matters to the reader, add an English gloss next to it:
|
|
326
|
+
`สอบทาน` (reviewed).
|
|
327
|
+
|
|
245
328
|
## Working on the repo itself
|
|
246
329
|
|
|
247
330
|
```bash
|
|
@@ -271,3 +354,10 @@ settfex is **not officially affiliated** with SET or TFEX. It reads **public** m
|
|
|
271
354
|
Browser impersonation and session caching exist to access that public data reliably and to
|
|
272
355
|
*reduce* request volume (~25× fewer requests) — not to evade rate limits or terms of service.
|
|
273
356
|
Respect both.
|
|
357
|
+
|
|
358
|
+
**If you are sweeping many symbols, budget it.** These are other people's servers, and they push
|
|
359
|
+
back: a 929-symbol sweep at concurrency 8 drew connection resets and then a WAF block page — an
|
|
360
|
+
**HTTP 200 whose body reads `Request Rejected`** — for every request for about an hour
|
|
361
|
+
(2026-09-20). Use concurrency 1 with jittered pauses, decide a request budget before you start,
|
|
362
|
+
prefer a stratified sample over a census, and **stop at the first block signal** rather than
|
|
363
|
+
retrying into it.
|