ezKit 1.9.0__tar.gz → 1.9.2__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.
- {ezkit-1.9.0/ezKit.egg-info → ezkit-1.9.2}/PKG-INFO +1 -1
- {ezkit-1.9.0 → ezkit-1.9.2}/ezKit/database.py +7 -6
- {ezkit-1.9.0 → ezkit-1.9.2}/ezKit/mongo.py +9 -0
- {ezkit-1.9.0 → ezkit-1.9.2}/ezKit/redis.py +5 -5
- ezkit-1.9.2/ezKit/stock.py +113 -0
- {ezkit-1.9.0 → ezkit-1.9.2}/ezKit/utils.py +42 -46
- {ezkit-1.9.0 → ezkit-1.9.2/ezKit.egg-info}/PKG-INFO +1 -1
- {ezkit-1.9.0 → ezkit-1.9.2}/setup.py +1 -1
- ezkit-1.9.0/ezKit/stock.py +0 -60
- {ezkit-1.9.0 → ezkit-1.9.2}/LICENSE +0 -0
- {ezkit-1.9.0 → ezkit-1.9.2}/MANIFEST.in +0 -0
- {ezkit-1.9.0 → ezkit-1.9.2}/README.md +0 -0
- {ezkit-1.9.0 → ezkit-1.9.2}/ezKit/__init__.py +0 -0
- {ezkit-1.9.0 → ezkit-1.9.2}/ezKit/bottle.py +0 -0
- {ezkit-1.9.0 → ezkit-1.9.2}/ezKit/bottle_extensions.py +0 -0
- {ezkit-1.9.0 → ezkit-1.9.2}/ezKit/cipher.py +0 -0
- {ezkit-1.9.0 → ezkit-1.9.2}/ezKit/cls.py +0 -0
- {ezkit-1.9.0 → ezkit-1.9.2}/ezKit/http.py +0 -0
- {ezkit-1.9.0 → ezkit-1.9.2}/ezKit/qywx.py +0 -0
- {ezkit-1.9.0 → ezkit-1.9.2}/ezKit/sendemail.py +0 -0
- {ezkit-1.9.0 → ezkit-1.9.2}/ezKit/token.py +0 -0
- {ezkit-1.9.0 → ezkit-1.9.2}/ezKit/xftp.py +0 -0
- {ezkit-1.9.0 → ezkit-1.9.2}/ezKit.egg-info/SOURCES.txt +0 -0
- {ezkit-1.9.0 → ezkit-1.9.2}/ezKit.egg-info/dependency_links.txt +0 -0
- {ezkit-1.9.0 → ezkit-1.9.2}/ezKit.egg-info/requires.txt +0 -0
- {ezkit-1.9.0 → ezkit-1.9.2}/ezKit.egg-info/top_level.txt +0 -0
- {ezkit-1.9.0 → ezkit-1.9.2}/setup.cfg +0 -0
@@ -10,6 +10,7 @@ from typing import Any
|
|
10
10
|
|
11
11
|
from loguru import logger
|
12
12
|
from sqlalchemy import CursorResult, Index, create_engine, text
|
13
|
+
from sqlalchemy.orm import DeclarativeBase
|
13
14
|
|
14
15
|
from . import utils
|
15
16
|
|
@@ -19,13 +20,13 @@ class Database():
|
|
19
20
|
|
20
21
|
engine = create_engine('sqlite://')
|
21
22
|
|
22
|
-
def __init__(self,
|
23
|
+
def __init__(self, target: str, **options):
|
23
24
|
"""Initiation"""
|
24
|
-
if
|
25
|
-
if utils.isTrue(
|
26
|
-
self.engine = create_engine(
|
25
|
+
if isinstance(target, str) and utils.isTrue(target, str):
|
26
|
+
if utils.isTrue(options, dict):
|
27
|
+
self.engine = create_engine(target, **options)
|
27
28
|
else:
|
28
|
-
self.engine = create_engine(
|
29
|
+
self.engine = create_engine(target)
|
29
30
|
else:
|
30
31
|
pass
|
31
32
|
|
@@ -45,7 +46,7 @@ class Database():
|
|
45
46
|
logger.exception(e)
|
46
47
|
return False
|
47
48
|
|
48
|
-
def metadata_init(self, base, **kwargs) -> bool:
|
49
|
+
def metadata_init(self, base: DeclarativeBase, **kwargs) -> bool:
|
49
50
|
# https://stackoverflow.com/questions/19175311/how-to-create-only-one-table-with-sqlalchemy
|
50
51
|
info = "Database init table"
|
51
52
|
try:
|
@@ -11,6 +11,15 @@ class Mongo():
|
|
11
11
|
|
12
12
|
client = MongoClient()
|
13
13
|
|
14
|
+
def __init__(self, target: str | dict):
|
15
|
+
"""Initiation"""
|
16
|
+
if isinstance(target, str) and utils.isTrue(target, str):
|
17
|
+
self.client = MongoClient(target)
|
18
|
+
elif isinstance(target, dict) and utils.isTrue(target, dict):
|
19
|
+
self.client = MongoClient(**target)
|
20
|
+
else:
|
21
|
+
pass
|
22
|
+
|
14
23
|
def close(self) -> bool:
|
15
24
|
"""client close"""
|
16
25
|
try:
|
@@ -16,12 +16,12 @@ class Redis:
|
|
16
16
|
# 这里修改以下参数: host, port, socket_timeout, socket_connect_timeout, charset
|
17
17
|
redis = RedisClient.Redis()
|
18
18
|
|
19
|
-
def __init__(self,
|
19
|
+
def __init__(self, target: str | dict):
|
20
20
|
"""Initiation"""
|
21
|
-
if isinstance(
|
22
|
-
self.redis = RedisClient.from_url(
|
23
|
-
elif isinstance(
|
24
|
-
self.redis = RedisClient.Redis(**
|
21
|
+
if isinstance(target, str) and utils.isTrue(target, str):
|
22
|
+
self.redis = RedisClient.from_url(target)
|
23
|
+
elif isinstance(target, dict) and utils.isTrue(target, dict):
|
24
|
+
self.redis = RedisClient.Redis(**target)
|
25
25
|
else:
|
26
26
|
pass
|
27
27
|
|
@@ -0,0 +1,113 @@
|
|
1
|
+
"""股票"""
|
2
|
+
import re
|
3
|
+
from copy import deepcopy
|
4
|
+
|
5
|
+
from loguru import logger
|
6
|
+
from pandas import DataFrame
|
7
|
+
|
8
|
+
from . import utils
|
9
|
+
|
10
|
+
|
11
|
+
def coderename(target: str | dict, restore: bool = False) -> str | dict | None:
|
12
|
+
"""代码重命名"""
|
13
|
+
|
14
|
+
# 正向:
|
15
|
+
# coderename('000001') => 'sz000001'
|
16
|
+
# coderename({'code': '000001', 'name': '平安银行'}) => {'code': 'sz000001', 'name': '平安银行'}
|
17
|
+
# 反向:
|
18
|
+
# coderename('sz000001', restore=True) => '000001'
|
19
|
+
# coderename({'code': 'sz000001', 'name': '平安银行'}) => {'code': '000001', 'name': '平安银行'}
|
20
|
+
|
21
|
+
# 判断参数类型
|
22
|
+
match True:
|
23
|
+
case True if True not in [isinstance(target, str), isinstance(target, dict)]:
|
24
|
+
logger.error("argument type error: target")
|
25
|
+
return None
|
26
|
+
case _:
|
27
|
+
pass
|
28
|
+
|
29
|
+
# 判断参数数据
|
30
|
+
match True:
|
31
|
+
case True if True not in [utils.isTrue(target, str), utils.isTrue(target, dict)]:
|
32
|
+
logger.error("argument data error: data")
|
33
|
+
return None
|
34
|
+
case _:
|
35
|
+
pass
|
36
|
+
|
37
|
+
try:
|
38
|
+
|
39
|
+
# 初始化
|
40
|
+
code_object: dict = {}
|
41
|
+
code_name: str | dict = ""
|
42
|
+
|
43
|
+
# 判断 target 是 string 还是 dictionary
|
44
|
+
if isinstance(target, str) and utils.isTrue(target, str):
|
45
|
+
code_name = target
|
46
|
+
elif isinstance(target, dict) and utils.isTrue(target, dict):
|
47
|
+
code_object = deepcopy(target)
|
48
|
+
code_name = str(deepcopy(target["code"]))
|
49
|
+
else:
|
50
|
+
return None
|
51
|
+
|
52
|
+
# 是否还原
|
53
|
+
if utils.isTrue(restore, bool):
|
54
|
+
if len(code_name) == 8 and re.match(r"^(sz|sh)", code_name):
|
55
|
+
code_name = deepcopy(code_name[2:8])
|
56
|
+
else:
|
57
|
+
return None
|
58
|
+
else:
|
59
|
+
if code_name[0:2] == "00":
|
60
|
+
code_name = f"sz{code_name}"
|
61
|
+
elif code_name[0:2] == "60":
|
62
|
+
code_name = f"sh{code_name}"
|
63
|
+
else:
|
64
|
+
return None
|
65
|
+
|
66
|
+
# 返回结果
|
67
|
+
if utils.isTrue(target, str):
|
68
|
+
return code_name
|
69
|
+
|
70
|
+
if utils.isTrue(target, dict):
|
71
|
+
code_object["code"] = code_name
|
72
|
+
return code_object
|
73
|
+
|
74
|
+
return None
|
75
|
+
|
76
|
+
except Exception as e:
|
77
|
+
logger.exception(e)
|
78
|
+
return None
|
79
|
+
|
80
|
+
|
81
|
+
# --------------------------------------------------------------------------------------------------
|
82
|
+
|
83
|
+
|
84
|
+
def kdj_vector(df: DataFrame, cp: int = 9, sp1: int = 3, sp2: int = 3) -> DataFrame | None:
|
85
|
+
"""KDJ计算器"""
|
86
|
+
|
87
|
+
# 计算周期:Calculation Period, 也可使用 Lookback Period 表示回溯周期, 指用于计算指标值的时间周期.
|
88
|
+
# 移动平均周期: Smoothing Period 或 Moving Average Period, 指对指标进行平滑处理时采用的周期.
|
89
|
+
# 同花顺默认参数: 9 3 3
|
90
|
+
# https://www.daimajiaoliu.com/daima/4ed4ffa26100400
|
91
|
+
# 说明: KDJ 指标的中文名称又叫随机指标, 融合了动量观念、强弱指标和移动平均线的一些优点, 能够比较迅速、快捷、直观地研判行情, 被广泛用于股市的中短期趋势分析.
|
92
|
+
# 有采用 ewm 使用 com=2 的, 但是如果使用 com=2 在默认值的情况下KDJ值是正确的.
|
93
|
+
# 但是非默认值, 比如调整参数, 尝试慢速 KDJ 时就不对了, 最终采用 alpha = 1/m 的情况, 对比同花顺数据, 是正确的.
|
94
|
+
|
95
|
+
# 判断参数类型
|
96
|
+
match True:
|
97
|
+
case True if not isinstance(df, DataFrame):
|
98
|
+
logger.error("argument type error: df")
|
99
|
+
return None
|
100
|
+
case _:
|
101
|
+
pass
|
102
|
+
|
103
|
+
try:
|
104
|
+
low_list = df['low'].rolling(cp).min()
|
105
|
+
high_list = df['high'].rolling(cp).max()
|
106
|
+
rsv = (df['close'] - low_list) / (high_list - low_list) * 100
|
107
|
+
df['K'] = rsv.ewm(alpha=1 / sp1, adjust=False).mean()
|
108
|
+
df['D'] = df['K'].ewm(alpha=1 / sp2, adjust=False).mean()
|
109
|
+
df['J'] = (3 * df['K']) - (2 * df['D'])
|
110
|
+
return df
|
111
|
+
except Exception as e:
|
112
|
+
logger.exception(e)
|
113
|
+
return None
|
@@ -35,23 +35,21 @@ def isTrue(
|
|
35
35
|
true_list: list | tuple | set | str | None = None,
|
36
36
|
false_list: list | tuple | set | str | None = None
|
37
37
|
) -> bool:
|
38
|
-
"""
|
39
|
-
检查对象类型以及对象数据是否为 True
|
40
|
-
|
41
|
-
常见类型:
|
42
|
-
|
43
|
-
Boolean bool False
|
44
|
-
Numbers int/float 0/0.0
|
45
|
-
String str ""
|
46
|
-
List list/tuple/set []/()/{}
|
47
|
-
Dictionary dict {}
|
48
|
-
|
49
|
-
查看变量类型: type(x)
|
38
|
+
"""检查对象类型以及对象数据是否为 True"""
|
50
39
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
40
|
+
# 常见类型:
|
41
|
+
#
|
42
|
+
# Boolean bool False
|
43
|
+
# Numbers int/float 0/0.0
|
44
|
+
# String str ""
|
45
|
+
# List list/tuple/set []/()/{}
|
46
|
+
# Dictionary dict {}
|
47
|
+
#
|
48
|
+
# 查看变量类型: type(x)
|
49
|
+
#
|
50
|
+
# 判断变量类型: isinstance(x, str)
|
51
|
+
#
|
52
|
+
# 函数使用 callable(func) 判断
|
55
53
|
|
56
54
|
try:
|
57
55
|
|
@@ -411,9 +409,33 @@ def list_print_by_step(
|
|
411
409
|
step: int,
|
412
410
|
separator: str = " "
|
413
411
|
) -> bool:
|
414
|
-
"""
|
415
|
-
|
416
|
-
|
412
|
+
"""根据 步长 和 分隔符 有规律的打印列表中的数据"""
|
413
|
+
|
414
|
+
# 判断参数类型
|
415
|
+
match True:
|
416
|
+
case True if not isinstance(data, list):
|
417
|
+
logger.error("argument type error: data")
|
418
|
+
return False
|
419
|
+
case True if not isinstance(step, int):
|
420
|
+
logger.error("argument type error: step")
|
421
|
+
return False
|
422
|
+
case True if not isinstance(separator, str):
|
423
|
+
logger.error("argument type error: separator")
|
424
|
+
return False
|
425
|
+
case _:
|
426
|
+
pass
|
427
|
+
|
428
|
+
# 判断参数数据
|
429
|
+
match True:
|
430
|
+
case True if not isTrue(data, list):
|
431
|
+
logger.error("argument data error: data")
|
432
|
+
return False
|
433
|
+
case True if not isTrue(step, int):
|
434
|
+
logger.error("argument data error: step")
|
435
|
+
return False
|
436
|
+
case _:
|
437
|
+
pass
|
438
|
+
|
417
439
|
try:
|
418
440
|
|
419
441
|
# result: list = []
|
@@ -431,31 +453,6 @@ def list_print_by_step(
|
|
431
453
|
|
432
454
|
# return True
|
433
455
|
|
434
|
-
# 判断参数类型
|
435
|
-
match True:
|
436
|
-
case True if isinstance(data, list) is False:
|
437
|
-
logger.error("argument type error: data")
|
438
|
-
return False
|
439
|
-
case True if isinstance(step, int) is False:
|
440
|
-
logger.error("argument type error: step")
|
441
|
-
return False
|
442
|
-
case True if isinstance(separator, str) is False:
|
443
|
-
logger.error("argument type error: separator")
|
444
|
-
return False
|
445
|
-
case _:
|
446
|
-
pass
|
447
|
-
|
448
|
-
# 判断参数数据
|
449
|
-
match True:
|
450
|
-
case True if not isTrue(data, list):
|
451
|
-
logger.error("argument error: data")
|
452
|
-
return False
|
453
|
-
case True if not isTrue(step, int):
|
454
|
-
logger.error("argument error: step")
|
455
|
-
return False
|
456
|
-
case _:
|
457
|
-
pass
|
458
|
-
|
459
456
|
# 打印
|
460
457
|
for i, v in enumerate(data):
|
461
458
|
if i > 0 and i % step == 0:
|
@@ -1340,8 +1337,7 @@ def increment_version(
|
|
1340
1337
|
|
1341
1338
|
|
1342
1339
|
def make_directory(
|
1343
|
-
directory: str
|
1344
|
-
debug: bool = False
|
1340
|
+
directory: str
|
1345
1341
|
) -> bool:
|
1346
1342
|
"""创建目录"""
|
1347
1343
|
try:
|
ezkit-1.9.0/ezKit/stock.py
DELETED
@@ -1,60 +0,0 @@
|
|
1
|
-
"""股票"""
|
2
|
-
from copy import deepcopy
|
3
|
-
from typing import Any
|
4
|
-
|
5
|
-
from loguru import logger
|
6
|
-
|
7
|
-
from . import utils
|
8
|
-
|
9
|
-
|
10
|
-
def coderename(target: str | dict, restore: bool = False) -> str | dict | None:
|
11
|
-
"""
|
12
|
-
正向:
|
13
|
-
coderename('000001') => 'sz000001'
|
14
|
-
coderename({'code': '000001', 'name': '平安银行'}) => {'code': 'sz000001', 'name': '平安银行'}
|
15
|
-
反向:
|
16
|
-
coderename('sz000001', restore=True) => '000001'
|
17
|
-
coderename({'code': 'sz000001', 'name': '平安银行'}) => {'code': '000001', 'name': '平安银行'}
|
18
|
-
"""
|
19
|
-
|
20
|
-
try:
|
21
|
-
|
22
|
-
_object: Any = None
|
23
|
-
_code_name: Any = None
|
24
|
-
|
25
|
-
# 判断 target 是 string 还是 dictionary
|
26
|
-
if isinstance(target, str) and utils.isTrue(target, str):
|
27
|
-
_code_name = target
|
28
|
-
elif isinstance(target, dict) and utils.isTrue(target, dict):
|
29
|
-
_object = deepcopy(target)
|
30
|
-
_code_name = str(deepcopy(target["code"]))
|
31
|
-
else:
|
32
|
-
return None
|
33
|
-
|
34
|
-
# 是否还原
|
35
|
-
if restore:
|
36
|
-
if len(_code_name) == 8 and ("sh" in _code_name or "sz" in _code_name):
|
37
|
-
_code_name = _code_name[2:8]
|
38
|
-
else:
|
39
|
-
return None
|
40
|
-
else:
|
41
|
-
if _code_name[0:2] == "00":
|
42
|
-
_code_name = "sz" + _code_name
|
43
|
-
elif _code_name[0:2] == "60":
|
44
|
-
_code_name = "sh" + _code_name
|
45
|
-
else:
|
46
|
-
return None
|
47
|
-
|
48
|
-
# 返回结果
|
49
|
-
if utils.isTrue(target, str):
|
50
|
-
return _code_name
|
51
|
-
|
52
|
-
if utils.isTrue(target, dict):
|
53
|
-
_object["code"] = _code_name
|
54
|
-
return _object
|
55
|
-
|
56
|
-
return None
|
57
|
-
|
58
|
-
except Exception as e:
|
59
|
-
logger.exception(e)
|
60
|
-
return None
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|