siat 3.11.3__py3-none-any.whl → 3.11.4__py3-none-any.whl

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.
siat/common.py CHANGED
@@ -2889,7 +2889,7 @@ if __name__=='__main__':
2889
2889
  file='stooq.py'
2890
2890
  package='pandas_datareader'
2891
2891
 
2892
- def fix_package(file='stooq.py',package='pandas_datareader'):
2892
+ def fix_package_x(file='stooq.py',package='pandas_datareader'):
2893
2893
  """
2894
2894
  功能:修复stooq.py,使用siat包中的stooq.py覆盖pandas_datareader中的同名文件
2895
2895
  注意:执行本程序需要系统管理员权限,可以系统管理员权限启动Jupyter或Spyder
@@ -2899,6 +2899,7 @@ def fix_package(file='stooq.py',package='pandas_datareader'):
2899
2899
  stooq.py pandas_datareader
2900
2900
  bond_zh_sina.py akshare
2901
2901
 
2902
+ 注意:在Python 3.13出错,暂时废弃!
2902
2903
  """
2903
2904
  #判断操作系统
2904
2905
  import sys; czxt=sys.platform
@@ -2923,7 +2924,7 @@ def fix_package(file='stooq.py',package='pandas_datareader'):
2923
2924
 
2924
2925
  #目标地址
2925
2926
  cmdstr1='import '+package
2926
- exec(cmdstr1) #无返回值地执行字符串代码
2927
+ exec(cmdstr1) #无返回值地执行字符串代码,此句在Python 3.13后台不管用了!
2927
2928
  #import pandas_datareader
2928
2929
  #objpath=pandas_datareader.__path__[0]
2929
2930
  cmdstr2=package+'.__path__[0]'
@@ -2957,6 +2958,54 @@ def fix_package(file='stooq.py',package='pandas_datareader'):
2957
2958
 
2958
2959
  return
2959
2960
 
2961
+ def fix_package(file='stooq.py', package='pandas_datareader'):
2962
+ """
2963
+ 功能:修复指定包中的文件,例如将 siat 中的 stooq.py 覆盖 pandas_datareader 中的同名文件。
2964
+ 注意:执行本程序需要系统管理员权限,可以系统管理员权限启动 Jupyter 或 Spyder。
2965
+ """
2966
+
2967
+ import sys
2968
+ import importlib.util
2969
+ import siat
2970
+ from shutil import copyfile
2971
+
2972
+ # 判断操作系统
2973
+ platform = sys.platform
2974
+ if platform.startswith('win'):
2975
+ os_type = 'windows'
2976
+ elif platform == 'darwin':
2977
+ os_type = 'mac'
2978
+ elif platform.startswith('linux'):
2979
+ os_type = 'linux'
2980
+ else:
2981
+ os_type = 'unknown'
2982
+
2983
+ # 获取源文件路径
2984
+ src_path = siat.__path__[0].replace("\\", "/") if os_type == 'windows' else siat.__path__[0]
2985
+ src_file = f"{src_path}/{file}"
2986
+
2987
+ # 获取目标包路径
2988
+ spec = importlib.util.find_spec(package)
2989
+ if spec is None or not spec.submodule_search_locations:
2990
+ print(f" #Error(fix_package): Package '{package}' not found.")
2991
+ return
2992
+
2993
+ obj_path = spec.submodule_search_locations[0].replace("\\", "/") if os_type == 'windows' else spec.submodule_search_locations[0]
2994
+ obj_file = f"{obj_path}/{file}"
2995
+
2996
+ # 执行文件复制
2997
+ try:
2998
+ copyfile(src_file, obj_file)
2999
+ except IOError as e:
3000
+ print(f" #Error(fix_package): Unable to copy file. {e}")
3001
+ print(" Solution: manually copy the file", src_file, "to the folder", obj_path)
3002
+ except Exception as e:
3003
+ print(f" #Error(fix_package): Unexpected error: {e}")
3004
+ else:
3005
+ print(f" Overrided '{file}' in '{package}'")
3006
+ print(" Please RESTART Python kernel before using siat")
3007
+
3008
+ return
2960
3009
 
2961
3010
 
2962
3011
 
@@ -0,0 +1,147 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ 本模块功能:转换ipynb文件为pdf,带有可跳转的目录(目前一级标题定位还不准确,二级以下目录定位较准确,但已可用)
4
+ 所属工具包:证券投资分析工具SIAT
5
+ SIAT:Security Investment Analysis Tool
6
+ 创建日期:2025年7月8日
7
+ 最新修订日期:2025年7月8日
8
+ 作者:王德宏 (WANG Dehong, Peter)
9
+ 作者单位:北京外国语大学国际商学院
10
+ 作者邮件:wdehong2000@163.com
11
+ 版权所有:王德宏
12
+ 用途限制:仅限研究与教学使用。
13
+ 特别声明:作者不对使用本工具进行证券投资导致的任何损益负责!
14
+ """
15
+
16
+ #==============================================================================
17
+
18
+ # 首次运行前,请安装依赖:
19
+ # !pip install nbformat nbconvert playwright pymupdf nest_asyncio
20
+ # !playwright install
21
+
22
+ import os
23
+ import re
24
+ import tempfile
25
+ import asyncio
26
+
27
+ import nest_asyncio
28
+ import nbformat
29
+ from nbconvert import HTMLExporter
30
+ from playwright.async_api import async_playwright
31
+ import fitz # PyMuPDF
32
+
33
+ nest_asyncio.apply() # 使 asyncio.run 在 Notebook 中可用
34
+
35
+ def ipynb2pdf(ipynb_path: str) -> str:
36
+ """
37
+ 将 .ipynb 转为带可跳转目录书签的 PDF。
38
+ 返回生成的 PDF 文件路径。
39
+ """
40
+ if not os.path.isfile(ipynb_path):
41
+ raise FileNotFoundError(f"找不到文件:{ipynb_path}")
42
+ output_pdf = ipynb_path[:-6] + ".pdf"
43
+
44
+ print(f"Converting to PDF ...")
45
+
46
+ # 1. 读 notebook → 提取目录结构
47
+ nb = nbformat.read(ipynb_path, as_version=4)
48
+ toc = _extract_toc(nb)
49
+
50
+ # 2. nb → HTML
51
+ exporter = HTMLExporter()
52
+ html_body, _ = exporter.from_notebook_node(nb)
53
+
54
+ # 3. 临时写 HTML / PDF
55
+ with tempfile.NamedTemporaryFile("w", suffix=".html", encoding="utf-8", delete=False) as th:
56
+ th.write(html_body)
57
+ html_path = th.name
58
+ with tempfile.NamedTemporaryFile(suffix=".pdf", delete=False) as tp:
59
+ tmp_pdf = tp.name
60
+
61
+ # 4. Playwright 渲染 HTML → PDF
62
+ asyncio.run(_html_to_pdf(html_path, tmp_pdf))
63
+
64
+ # 5. PyMuPDF 添加书签
65
+ _add_bookmarks(tmp_pdf, output_pdf, toc)
66
+
67
+ # 6. 清理
68
+ os.unlink(html_path)
69
+ os.unlink(tmp_pdf)
70
+
71
+ from pathlib import Path
72
+ full_path = Path(output_pdf)
73
+ # 提取文件名
74
+ filename = full_path.name # 'report.pdf'
75
+ # 提取路径
76
+ directory = full_path.parent # PosixPath('/Users/peter/Documents')
77
+
78
+ print(f"✅ {filename} is created with TOC")
79
+ print(f"✅ It is in {directory}")
80
+
81
+ #return output_pdf
82
+ return
83
+
84
+ async def _html_to_pdf(html_path: str, pdf_path: str):
85
+ async with async_playwright() as p:
86
+ browser = await p.chromium.launch()
87
+ page = await browser.new_page()
88
+ await page.goto(f"file://{html_path}")
89
+ await page.pdf(
90
+ path=pdf_path,
91
+ #format="A4",
92
+ format="A3",
93
+ print_background=True,
94
+ margin={"top":"20mm","bottom":"20mm","left":"20mm","right":"20mm"},
95
+ )
96
+ await browser.close()
97
+
98
+ def _extract_toc(nb_node) -> list[tuple[int,str]]:
99
+ """
100
+ 从每个 markdown 单元首行提取 # 级别和标题文本,
101
+ 返回 [(level, title), …]
102
+ """
103
+ toc = []
104
+ for cell in nb_node.cells:
105
+ if cell.cell_type != "markdown":
106
+ continue
107
+ first = cell.source.strip().splitlines()[0]
108
+ m = re.match(r"^(#{1,6})\s+(.*)", first)
109
+ if m:
110
+ toc.append((len(m.group(1)), m.group(2).strip()))
111
+ return toc
112
+
113
+ def _add_bookmarks(input_pdf: str, output_pdf: str, toc: list[tuple[int,str]]):
114
+ """
115
+ 用 PyMuPDF 打开临时 PDF,按 toc 列表查找页码,
116
+ 然后用 set_toc() 批量写入书签。
117
+ """
118
+ doc = fitz.open(input_pdf)
119
+ outline = []
120
+ for level, title in toc:
121
+ page_num = 1
122
+ # 搜索标题出现在第几页(0-based → +1)
123
+ for i in range(doc.page_count):
124
+ if title in doc.load_page(i).get_text():
125
+ page_num = i + 1
126
+ break
127
+ outline.append([level, title, page_num])
128
+
129
+ # 批量设置目录书签
130
+ doc.set_toc(outline)
131
+ doc.save(output_pdf)
132
+
133
+ # 使用示例(另起一个 cell 运行):
134
+ # ipynb = globals().get("__session__")
135
+ # ipynb2pdf(ipynb)
136
+
137
+
138
+ #==============================================================================
139
+
140
+ #==============================================================================
141
+ #==============================================================================
142
+ #==============================================================================
143
+ #==============================================================================
144
+ #==============================================================================
145
+ #==============================================================================
146
+ #==============================================================================
147
+ #==============================================================================
@@ -0,0 +1,133 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ 本模块功能:转换ipynb文件为pdf,带有可跳转的目录(目前一级标题定位还不准确,二级以下目录定位较准确,但已可用)
4
+ 所属工具包:证券投资分析工具SIAT
5
+ SIAT:Security Investment Analysis Tool
6
+ 创建日期:2025年7月8日
7
+ 最新修订日期:2025年7月8日
8
+ 作者:王德宏 (WANG Dehong, Peter)
9
+ 作者单位:北京外国语大学国际商学院
10
+ 作者邮件:wdehong2000@163.com
11
+ 版权所有:王德宏
12
+ 用途限制:仅限研究与教学使用。
13
+ 特别声明:作者不对使用本工具进行证券投资导致的任何损益负责!
14
+ """
15
+
16
+ #==============================================================================
17
+
18
+ # 首次运行前,请安装依赖:
19
+ # !pip install nbformat nbconvert weasyprint pymupdf nest_asyncio
20
+ # !playwright install
21
+
22
+ import os
23
+ import re
24
+ import tempfile
25
+ import nbformat
26
+ from nbconvert import HTMLExporter
27
+ from weasyprint import HTML, CSS
28
+ import fitz # PyMuPDF
29
+
30
+ def ipynb2pdf(ipynb_path: str) -> str:
31
+ """
32
+ 将 .ipynb 转为带可跳转目录书签的 PDF。
33
+ 返回生成的 PDF 文件路径。
34
+ """
35
+ if not os.path.isfile(ipynb_path):
36
+ raise FileNotFoundError(f"找不到文件:{ipynb_path}")
37
+ output_pdf = ipynb_path[:-6] + ".pdf"
38
+
39
+ print(f"📄 正在转换为 PDF ...")
40
+
41
+ # 1. 读取 notebook → 提取目录结构
42
+ nb = nbformat.read(ipynb_path, as_version=4)
43
+ toc = _extract_toc(nb)
44
+
45
+ # 2. notebook → HTML
46
+ exporter = HTMLExporter()
47
+ html_body, _ = exporter.from_notebook_node(nb)
48
+
49
+ # 3. 写入临时 HTML 文件
50
+ with tempfile.NamedTemporaryFile("w", suffix=".html", encoding="utf-8", delete=False) as th:
51
+ th.write(html_body)
52
+ html_path = th.name
53
+
54
+ # 4. 使用 WeasyPrint 渲染 HTML → PDF
55
+ tmp_pdf = tempfile.NamedTemporaryFile(suffix=".pdf", delete=False).name
56
+ _html_to_pdf(html_path, tmp_pdf)
57
+
58
+ # 5. 使用 PyMuPDF 添加书签
59
+ _add_bookmarks(tmp_pdf, output_pdf, toc)
60
+
61
+ # 6. 清理临时文件
62
+ os.unlink(html_path)
63
+ os.unlink(tmp_pdf)
64
+
65
+ print(f"✅ PDF 已生成:{output_pdf}")
66
+ return output_pdf
67
+
68
+ def _html_to_pdf(html_path: str, pdf_path: str):
69
+ """
70
+ 使用 WeasyPrint 将 HTML 渲染为 PDF。
71
+ """
72
+ HTML(filename=html_path).write_pdf(
73
+ pdf_path,
74
+ stylesheets=[CSS(string="""
75
+ @page {
76
+ size: A4;
77
+ margin: 20mm;
78
+ }
79
+ body {
80
+ font-family: 'Arial', sans-serif;
81
+ line-height: 1.6;
82
+ }
83
+ """)]
84
+ )
85
+
86
+ def _extract_toc(nb_node) -> list[tuple[int, str]]:
87
+ """
88
+ 从每个 markdown 单元首行提取 # 级别和标题文本,
89
+ 返回 [(level, title), …]
90
+ """
91
+ toc = []
92
+ for cell in nb_node.cells:
93
+ if cell.cell_type != "markdown":
94
+ continue
95
+ first = cell.source.strip().splitlines()[0]
96
+ m = re.match(r"^(#{1,6})\s+(.*)", first)
97
+ if m:
98
+ toc.append((len(m.group(1)), m.group(2).strip()))
99
+ return toc
100
+
101
+ def _add_bookmarks(input_pdf: str, output_pdf: str, toc: list[tuple[int, str]]):
102
+ """
103
+ 用 PyMuPDF 打开临时 PDF,按 toc 列表查找页码,
104
+ 然后用 set_toc() 批量写入书签。
105
+ """
106
+ doc = fitz.open(input_pdf)
107
+ outline = []
108
+ for level, title in toc:
109
+ page_num = 1
110
+ for i in range(doc.page_count):
111
+ if title in doc.load_page(i).get_text():
112
+ page_num = i + 1
113
+ break
114
+ outline.append([level, title, page_num])
115
+ doc.set_toc(outline)
116
+ doc.save(output_pdf)
117
+
118
+
119
+ # 使用示例(另起一个 cell 运行):
120
+ # ipynb = globals().get("__session__")
121
+ # ipynb2pdf(ipynb)
122
+
123
+
124
+ #==============================================================================
125
+
126
+ #==============================================================================
127
+ #==============================================================================
128
+ #==============================================================================
129
+ #==============================================================================
130
+ #==============================================================================
131
+ #==============================================================================
132
+ #==============================================================================
133
+ #==============================================================================
siat/save2pdf.py CHANGED
@@ -81,6 +81,9 @@ def ipynb2pdf(ipynb_path: str) -> str:
81
81
  #return output_pdf
82
82
  return
83
83
 
84
+ #==============================================================================
85
+ """
86
+ # 异步版本1
84
87
  async def _html_to_pdf(html_path: str, pdf_path: str):
85
88
  async with async_playwright() as p:
86
89
  browser = await p.chromium.launch()
@@ -94,6 +97,46 @@ async def _html_to_pdf(html_path: str, pdf_path: str):
94
97
  margin={"top":"20mm","bottom":"20mm","left":"20mm","right":"20mm"},
95
98
  )
96
99
  await browser.close()
100
+ """
101
+ import nest_asyncio
102
+ import asyncio
103
+ from playwright.async_api import async_playwright
104
+
105
+ nest_asyncio.apply()
106
+
107
+ async def _html_to_pdf(html_path: str, pdf_path: str):
108
+ async with async_playwright() as p:
109
+ browser = await p.chromium.launch()
110
+ page = await browser.new_page()
111
+ await page.goto(f"file://{html_path}")
112
+ await page.pdf(
113
+ path=pdf_path,
114
+ format="A3",
115
+ print_background=True,
116
+ margin={"top": "20mm", "bottom": "20mm", "left": "20mm", "right": "20mm"},
117
+ )
118
+ await browser.close()
119
+
120
+
121
+
122
+ """
123
+ # 同步版本:不能在Jupyter中使用
124
+ from playwright.sync_api import sync_playwright
125
+
126
+ def _html_to_pdf(html_path: str, pdf_path: str):
127
+ with sync_playwright() as p:
128
+ browser = p.chromium.launch()
129
+ page = browser.new_page()
130
+ page.goto(f"file://{html_path}")
131
+ page.pdf(
132
+ path=pdf_path,
133
+ format="A3",
134
+ print_background=True,
135
+ margin={"top": "20mm", "bottom": "20mm", "left": "20mm", "right": "20mm"},
136
+ )
137
+ browser.close()
138
+ """
139
+ #==============================================================================
97
140
 
98
141
  def _extract_toc(nb_node) -> list[tuple[int,str]]:
99
142
  """
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: siat
3
- Version: 3.11.3
3
+ Version: 3.11.4
4
4
  Summary: Securities Investment Analysis Tools (siat)
5
5
  Home-page: https://pypi.org/project/siat/
6
6
  Author: Prof. WANG Dehong, International Business School, Beijing Foreign Studies University
@@ -11,7 +11,7 @@ Project-URL: Homepage, https://pypi.org/project/siat/
11
11
  Keywords: investment,finance,technical analysis,siat
12
12
  Classifier: Programming Language :: Python :: 3
13
13
  Classifier: Operating System :: OS Independent
14
- Requires-Python: >=3.7
14
+ Requires-Python: <3.13,>=3.7
15
15
  Description-Content-Type: text/markdown
16
16
  License-File: LICENSE
17
17
  Requires-Dist: pandas-datareader
@@ -45,10 +45,12 @@ Requires-Dist: ipywidgets
45
45
  Requires-Dist: yahooquery
46
46
  Requires-Dist: alpha-vantage
47
47
  Requires-Dist: tiingo[pandas]
48
- Requires-Dist: numpy <2
48
+ Requires-Dist: numpy<2
49
49
  Requires-Dist: playwright
50
50
  Requires-Dist: pymupdf
51
51
  Requires-Dist: pypandoc
52
+ Requires-Dist: python-docx
53
+ Requires-Dist: weasyprint
52
54
 
53
55
 
54
56
  # What is siat?
@@ -10,7 +10,7 @@ siat/bond_china.py,sha256=WzUhjYYk8tsr3BDWLQcpuj9DqNxTzBSIi_wuAOZ48kY,3082
10
10
  siat/bond_zh_sina.py,sha256=26BohGcS120utwqg9dJvdGm5OkuNpNu5bco80uOuQpU,4423
11
11
  siat/capm_beta.py,sha256=t8-xr90II0JzbjsTOZNpRze_mKTvBRXjwN2o0N0tgD8,30521
12
12
  siat/capm_beta2.py,sha256=S2x6PrWp_1FyzVmG2MVzCf7LlpfHHEJxroJH2b26DvQ,35989
13
- siat/common.py,sha256=GLNRbXP7uDA_pibWXJQ-St0o9ylhvRut0k9KpCQ70bI,193909
13
+ siat/common.py,sha256=BRFnwmYKhq00117PZK4tMD0gVfE2yncJInY1NEj5pyE,195772
14
14
  siat/compare_cross.py,sha256=3iP9TH2h3w27F2ARZc7FjKcErYCzWRc-TPiymOyoVtw,24171
15
15
  siat/copyrights.py,sha256=YMLjZb328YpFMR-s_GUu0HBgeGce3pV7DgRut8S3I7w,690
16
16
  siat/cryptocurrency.py,sha256=QSc4jK9VFlqBWVu-0th1BIMt8wC-5R5sWky3EaNupy0,27940
@@ -51,7 +51,9 @@ siat/risk_adjusted_return2.py,sha256=gCtHhfGNlV1wHqU9gfHJ_n17wRSyTMxc7lS8jgZ-GQk
51
51
  siat/risk_evaluation.py,sha256=xfgLSKlIWYmRJrIL4kn2k2hp9fyOMAzYGIhi9ImvKOw,88917
52
52
  siat/risk_free_rate.py,sha256=IBuRqA2kppdZsW4D4fapW7vnM5HMEXOn95A5r9Pkwlo,12384
53
53
  siat/save2docx.py,sha256=c43X3IGgfli4gg2VJilRaLzd_KCZX4yF_lLO2S9FvQA,12302
54
- siat/save2pdf.py,sha256=cB1L5lH2n6RfgubCLFR7a617OGnrtT9IQhWXWGncoFs,5114
54
+ siat/save2pdf-playwright-20250712.py,sha256=cB1L5lH2n6RfgubCLFR7a617OGnrtT9IQhWXWGncoFs,5114
55
+ siat/save2pdf-weasyprint-20250712.py,sha256=ZVZq5yT-grcmdY3qq8XXZ7OCDCGqvh66o2WfszoK9ws,4570
56
+ siat/save2pdf.py,sha256=Stz2aoKNMRbLFPTRHPW37GIZtRNLeLnlJYEg9wRyD3s,6437
55
57
  siat/sector_china.py,sha256=uLsDXdRBDVfgG6tnXWnQOTyDmyZfglVO9DRUYU2e3pk,157914
56
58
  siat/security_price2.py,sha256=DDiZ2dlv_TYPLhA8-gGb9i9xrl88r4rgSMEcxqQ6aU0,28065
57
59
  siat/security_prices.py,sha256=X3ip0q_m3OL3QRNRkr_lYQk-wsXLf6dWkFkyoZijhck,129368
@@ -73,8 +75,8 @@ siat/valuation.py,sha256=xGizcKJZ3ADLWWHm2TFQub18FxiDv2doQwBwbEqyqz0,51980
73
75
  siat/valuation_china.py,sha256=eSKIDckyjG8QkENlW_OKkqbQHno8pzDcomBO9iGNJVM,83079
74
76
  siat/var_model_validation.py,sha256=loqziBYO2p0xkeWm3Rb1rJsDhbcgAZ5aR9rBLRwLU5E,17624
75
77
  siat/yf_name.py,sha256=laNKMTZ9hdenGX3IZ7G0a2RLBKEWtUQJFY9CWuk_fp8,24058
76
- siat-3.11.3.dist-info/LICENSE,sha256=NTEMMROY9_4U1szoKC3N2BLHcDd_o5uTgqdVH8tbApw,1071
77
- siat-3.11.3.dist-info/METADATA,sha256=5NpbsFU3Bzzehbm1u5q8EFFX_61QA_ydPkJpXMGpHK8,8533
78
- siat-3.11.3.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
79
- siat-3.11.3.dist-info/top_level.txt,sha256=X5R8wrVviq8agwJFVRVDsufkuOJuit-1qAT_kXeptrY,17
80
- siat-3.11.3.dist-info/RECORD,,
78
+ siat-3.11.4.dist-info/LICENSE,sha256=NTEMMROY9_4U1szoKC3N2BLHcDd_o5uTgqdVH8tbApw,1071
79
+ siat-3.11.4.dist-info/METADATA,sha256=5H2KxclhYUVnbfSnv1bpVxXBNG8XdejEFdlK9GKFmto,8593
80
+ siat-3.11.4.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
81
+ siat-3.11.4.dist-info/top_level.txt,sha256=X5R8wrVviq8agwJFVRVDsufkuOJuit-1qAT_kXeptrY,17
82
+ siat-3.11.4.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.43.0)
2
+ Generator: setuptools (72.1.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
File without changes