logixbase 0.1.0__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.
- demos/__init__.py +0 -0
- demos/build_demo.py +11 -0
- demos/build_demo_exec.py +14 -0
- demos/concur_demo.py +67 -0
- demos/configer_demo.py +100 -0
- demos/coordinator_demo.py +70 -0
- demos/ctpgateway_demo.py +46 -0
- demos/demoproj/__init__.py +0 -0
- demos/demoproj/clear.py +2 -0
- demos/demoproj/except_file.py +1 -0
- demos/demoproj/main.py +12 -0
- demos/demoproj/test.py +5 -0
- demos/feeder_demo.py +120 -0
- demos/logger_demo.py +160 -0
- demos/process_manager_demo.py +180 -0
- demos/simple_engine.py +113 -0
- logixbase/__init__.py +10 -0
- logixbase/algolib/__init__.py +127 -0
- logixbase/algolib/basestat.py +365 -0
- logixbase/algolib/chart.py +435 -0
- logixbase/algolib/fin.py +37 -0
- logixbase/algolib/matops.py +124 -0
- logixbase/algolib/optimization.py +458 -0
- logixbase/algolib/regression.py +433 -0
- logixbase/algolib/stattest.py +37 -0
- logixbase/algolib/stochastic.py +341 -0
- logixbase/algolib/timeseries.py +565 -0
- logixbase/algolib/utils.py +88 -0
- logixbase/compiler/__init__.py +6 -0
- logixbase/compiler/build.py +238 -0
- logixbase/compiler/schema.py +11 -0
- logixbase/configer/__init__.py +7 -0
- logixbase/configer/hotreloader.py +125 -0
- logixbase/configer/loader.py +505 -0
- logixbase/configer/proxy.py +84 -0
- logixbase/configer/schema.py +8 -0
- logixbase/engine/__init__.py +13 -0
- logixbase/engine/base.py +365 -0
- logixbase/engine/manager.py +210 -0
- logixbase/executor/__init__.py +7 -0
- logixbase/executor/base.py +233 -0
- logixbase/executor/context.py +69 -0
- logixbase/executor/coordinator.py +262 -0
- logixbase/executor/main.py +271 -0
- logixbase/executor/payload.py +38 -0
- logixbase/executor/process.py +122 -0
- logixbase/executor/task.py +144 -0
- logixbase/executor/thread.py +71 -0
- logixbase/feeder/__init__.py +17 -0
- logixbase/feeder/base.py +113 -0
- logixbase/feeder/config/database.yaml +10 -0
- logixbase/feeder/config/tinysoft.yaml +260 -0
- logixbase/feeder/config/wind.yaml +15 -0
- logixbase/feeder/schema.py +19 -0
- logixbase/feeder/sqlfeeder.py +1954 -0
- logixbase/feeder/tqfeeder.py +320 -0
- logixbase/feeder/tsfeeder.py +939 -0
- logixbase/feeder/wfeeder.py +721 -0
- logixbase/gateway/__init__.py +14 -0
- logixbase/gateway/api/__init__.py +0 -0
- logixbase/gateway/base.py +113 -0
- logixbase/gateway/ctp.py +1554 -0
- logixbase/gateway/schema.py +15 -0
- logixbase/logger/__init__.py +7 -0
- logixbase/logger/config.py +25 -0
- logixbase/logger/constant.py +7 -0
- logixbase/logger/core.py +135 -0
- logixbase/logger/decorator.py +21 -0
- logixbase/logger/formatter.py +9 -0
- logixbase/logger/mpwriter.py +89 -0
- logixbase/logger/parser.py +32 -0
- logixbase/logger/utils.py +11 -0
- logixbase/logger/writer.py +88 -0
- logixbase/plugin/__init__.py +15 -0
- logixbase/plugin/base.py +169 -0
- logixbase/plugin/log_monitor.py +203 -0
- logixbase/plugin/manager.py +169 -0
- logixbase/plugin/progress.py +252 -0
- logixbase/protocol/__init__.py +23 -0
- logixbase/protocol/database.py +38 -0
- logixbase/protocol/feeder.py +18 -0
- logixbase/protocol/gateway.py +51 -0
- logixbase/protocol/mod.py +32 -0
- logixbase/protocol/plugin.py +43 -0
- logixbase/protocol/task.py +16 -0
- logixbase/trader/__init__.py +64 -0
- logixbase/trader/config.py +20 -0
- logixbase/trader/constant.py +221 -0
- logixbase/trader/schema.py +465 -0
- logixbase/trader/tool.py +948 -0
- logixbase/trader/utils.py +279 -0
- logixbase/utils/__init__.py +105 -0
- logixbase/utils/database.py +470 -0
- logixbase/utils/decorator.py +156 -0
- logixbase/utils/dthandler.py +406 -0
- logixbase/utils/schema.py +17 -0
- logixbase/utils/strmanip.py +17 -0
- logixbase/utils/tool.py +212 -0
- logixbase/utils/web.py +216 -0
- logixbase-0.1.0.dist-info/METADATA +677 -0
- logixbase-0.1.0.dist-info/RECORD +104 -0
- logixbase-0.1.0.dist-info/WHEEL +5 -0
- logixbase-0.1.0.dist-info/licenses/LICENSE +21 -0
- logixbase-0.1.0.dist-info/top_level.txt +2 -0
demos/__init__.py
ADDED
|
File without changes
|
demos/build_demo.py
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import subprocess
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
LOCAL_DIR = Path(__file__).parent
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
if __name__ == "__main__":
|
|
8
|
+
# Execute in cmd
|
|
9
|
+
command = ["python", str(LOCAL_DIR.joinpath("build_demo_exec.py")), "build_ext", "--inplace"]
|
|
10
|
+
process = subprocess.Popen(command)
|
|
11
|
+
process.wait()
|
demos/build_demo_exec.py
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
sys.path.append(str(Path(__file__).parent.parent))
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
from logixbase.compiler import BuildProject
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
if __name__ == "__main__":
|
|
12
|
+
self = BuildProject("Demoproject", r"D:\licx\codes\logixbase\demos\configs\compiler.ini", r"d:\logs")
|
|
13
|
+
self.start()
|
|
14
|
+
self.stop()
|
demos/concur_demo.py
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import time
|
|
2
|
+
import random
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
import sys
|
|
5
|
+
|
|
6
|
+
sys.path.append(str(Path(__file__).parent.parent))
|
|
7
|
+
|
|
8
|
+
from logixbase.executor import MultiTaskExecutor
|
|
9
|
+
from logixbase.logger import LogManager
|
|
10
|
+
|
|
11
|
+
# 示例函数(测试:参数组合、异常、内存返回)
|
|
12
|
+
def example_task(x, y, delay=0.1, logger=None):
|
|
13
|
+
time.sleep(delay + random.uniform(0, 0.3))
|
|
14
|
+
if x == -1:
|
|
15
|
+
raise ValueError("intentional error")
|
|
16
|
+
output = x ** 2 + y
|
|
17
|
+
logger.INFO(f"Task input: x={x}, y={y} -> output={output}")
|
|
18
|
+
return {"input": (x, y), "output": output, "memory_usage": random.uniform(10, 50)}
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def generate_param_combinations():
|
|
22
|
+
param_set = []
|
|
23
|
+
for x in range(-1, 5): # 包含一个错误任务(x = -1)
|
|
24
|
+
for y in [0, 1, 2]: # 多参数组合测试
|
|
25
|
+
param_set.append((x, y))
|
|
26
|
+
return param_set
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def run_executor_demo(mode='process'):
|
|
30
|
+
print(f"\n==== Running {mode.upper()} mode demo ====")
|
|
31
|
+
|
|
32
|
+
loger = LogManager.get_instance(use_mp=True if mode in ("process", "pool") else False,
|
|
33
|
+
log_path=r'd:\logs')
|
|
34
|
+
|
|
35
|
+
executor = MultiTaskExecutor(mode=mode)
|
|
36
|
+
executor.bind_share(logger=loger)
|
|
37
|
+
|
|
38
|
+
# 多任务组合参数测试
|
|
39
|
+
for x, y in generate_param_combinations():
|
|
40
|
+
executor.submit(example_task, x, y, delay=0.1, group='combi', tags=[f"x={x}", f"y={y}"], task_name=f"task_{x}_{y}")
|
|
41
|
+
|
|
42
|
+
# 执行任务
|
|
43
|
+
executor.start()
|
|
44
|
+
|
|
45
|
+
if mode == 'pool':
|
|
46
|
+
executor.join()
|
|
47
|
+
loger.start()
|
|
48
|
+
else:
|
|
49
|
+
loger.start()
|
|
50
|
+
executor.join()
|
|
51
|
+
loger.stop()
|
|
52
|
+
# 报告与导出
|
|
53
|
+
executor.report(r"d:\logs", "csv", True)
|
|
54
|
+
# 错误与取消任务处理测试
|
|
55
|
+
failed = [tid for tid in executor.get_task_ids() if executor.get_status(tid) == 'error']
|
|
56
|
+
if failed:
|
|
57
|
+
print(f"Retrying failed tasks: {failed}")
|
|
58
|
+
executor.retry_failed()
|
|
59
|
+
|
|
60
|
+
any_id = executor.get_task_ids()[0]
|
|
61
|
+
executor.cancel_task(any_id)
|
|
62
|
+
executor.rerun_cancelled()
|
|
63
|
+
|
|
64
|
+
if __name__ == "__main__":
|
|
65
|
+
run_executor_demo('thread')
|
|
66
|
+
# run_executor_demo('pool')
|
|
67
|
+
# run_executor_demo('process')
|
demos/configer_demo.py
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import multiprocessing
|
|
2
|
+
import time
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
import sys
|
|
5
|
+
|
|
6
|
+
sys.path.append(str(Path(__file__).parent.parent.joinpath('logixbase')))
|
|
7
|
+
|
|
8
|
+
from configer.loader import ConfigLoader
|
|
9
|
+
from configer.schema import AppConfig # 假设你已经在 schema.py 中定义好 AppConfig 结构
|
|
10
|
+
|
|
11
|
+
CONFIG_PATH = Path(".\configs") # 所有配置文件目录,需自行准备
|
|
12
|
+
|
|
13
|
+
def test_1_load_single_path_all_formats():
|
|
14
|
+
print("\n--- Test 1: 加载多格式文件(无热更新) ---")
|
|
15
|
+
loader = ConfigLoader(CONFIG_PATH)
|
|
16
|
+
loader.load()
|
|
17
|
+
print("数据库地址:", loader.config.database.host)
|
|
18
|
+
print("邮件SMTP:", loader.config.mail.host)
|
|
19
|
+
|
|
20
|
+
def test_2_ini_levels():
|
|
21
|
+
print("\n--- Test 2: 加载 INI 多层级(无热更新) ---")
|
|
22
|
+
loader = ConfigLoader(CONFIG_PATH, mode="prod")
|
|
23
|
+
loader.load()
|
|
24
|
+
print("Prod 模式密码:", loader.config.mail.password)
|
|
25
|
+
|
|
26
|
+
def test_3_single_file_load():
|
|
27
|
+
print("\n--- Test 3: 加载单文件(无热更新) ---")
|
|
28
|
+
for suffix in [".ini", ".yaml", ".py"]:
|
|
29
|
+
file = CONFIG_PATH / f"CFG.base{suffix}"
|
|
30
|
+
print(f"\n加载文件: {file}")
|
|
31
|
+
loader = ConfigLoader(file)
|
|
32
|
+
loader.load()
|
|
33
|
+
print("邮箱用户名:", loader.config.mail.username)
|
|
34
|
+
|
|
35
|
+
loader = ConfigLoader(CONFIG_PATH / "cfg.ini")
|
|
36
|
+
loader.load()
|
|
37
|
+
print(f"\n加载文件: {CONFIG_PATH / 'cfg.ini'}")
|
|
38
|
+
print("邮箱用户名:", loader.config.mail.username)
|
|
39
|
+
|
|
40
|
+
def test_4_single_proc_hot_reload():
|
|
41
|
+
print("\n--- Test 4: 单进程热更新测试(请手动修改配置文件观察) ---")
|
|
42
|
+
loader = ConfigLoader(CONFIG_PATH)
|
|
43
|
+
loader.load()
|
|
44
|
+
loader.start()
|
|
45
|
+
|
|
46
|
+
def on_change():
|
|
47
|
+
print(">>> 主进程回调: 新配置:", loader.config.mail.host)
|
|
48
|
+
|
|
49
|
+
loader.register_callback(on_change)
|
|
50
|
+
|
|
51
|
+
try:
|
|
52
|
+
while True:
|
|
53
|
+
time.sleep(2)
|
|
54
|
+
except KeyboardInterrupt:
|
|
55
|
+
loader.stop()
|
|
56
|
+
print("已停止热更新")
|
|
57
|
+
|
|
58
|
+
def worker_proc(loader: ConfigLoader):
|
|
59
|
+
def on_child_update():
|
|
60
|
+
print(f"[子进程] 配置已更新:当前SMTP = {loader.config.mail.host}")
|
|
61
|
+
loader.register_mp_proxy()
|
|
62
|
+
loader.register_proxy_callback(on_child_update)
|
|
63
|
+
while True:
|
|
64
|
+
time.sleep(2)
|
|
65
|
+
|
|
66
|
+
def test_5_multi_proc_hot_reload():
|
|
67
|
+
print("\n--- Test 5: 多进程热更新测试(请手动修改配置文件观察) ---")
|
|
68
|
+
loader = ConfigLoader(CONFIG_PATH, use_proxy=True)
|
|
69
|
+
loader.load()
|
|
70
|
+
|
|
71
|
+
# 启动子进程
|
|
72
|
+
processes = []
|
|
73
|
+
for _ in range(2):
|
|
74
|
+
p = multiprocessing.Process(target=worker_proc, args=(loader,))
|
|
75
|
+
p.start()
|
|
76
|
+
processes.append(p)
|
|
77
|
+
|
|
78
|
+
def on_main_update():
|
|
79
|
+
print("[主进程] 配置已更新:当前数据库地址 =", loader.config.database.host)
|
|
80
|
+
|
|
81
|
+
loader.register_callback(on_main_update)
|
|
82
|
+
loader.start(CONFIG_PATH)
|
|
83
|
+
|
|
84
|
+
try:
|
|
85
|
+
while True:
|
|
86
|
+
time.sleep(2)
|
|
87
|
+
except KeyboardInterrupt:
|
|
88
|
+
for p in processes:
|
|
89
|
+
p.terminate()
|
|
90
|
+
loader.stop()
|
|
91
|
+
print("已终止所有子进程与热更新")
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
if __name__ == "__main__":
|
|
95
|
+
# 执行入口(如需测试,请取消注释一项)
|
|
96
|
+
# test_1_load_single_path_all_formats()
|
|
97
|
+
# test_2_ini_levels()
|
|
98
|
+
# test_3_single_file_load()
|
|
99
|
+
# test_4_single_proc_hot_reload()
|
|
100
|
+
test_5_multi_proc_hot_reload()
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import time
|
|
2
|
+
import sys
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
sys.path.append(str(Path(__file__).parent.parent))
|
|
6
|
+
|
|
7
|
+
from logixbase.logger import LogManager
|
|
8
|
+
from logixbase.executor import Coordinator
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def once_task(x, y, sum_val, from_upstream, logger=None):
|
|
12
|
+
"""Once 模式任务:执行一次并返回结果字典。"""
|
|
13
|
+
logger.INFO(f"[ONCE] x={x}, y={y}, sum_val={sum_val}, from_upstream={from_upstream}")
|
|
14
|
+
return {"x": x, "y": y, "sum_val": sum_val, "from_upstream": from_upstream}
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def hybrid_task(prefix, from_upstream, logger=None):
|
|
18
|
+
"""Hybrid 模式任务:每轮处理上游数据并返回字符串。"""
|
|
19
|
+
logger.INFO(f"[HYBRID] prefix={prefix}, from_upstream={from_upstream}")
|
|
20
|
+
return f"{prefix}-{from_upstream}"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def loop_task(name, req_queue=None, pub_queue=None, stop_event=None, logger=None):
|
|
24
|
+
"""Loop 模式任务:持续监听 req_queue 并将处理结果推入 pub_queue。"""
|
|
25
|
+
logger.INFO(f"[LOOP] {name} listening...")
|
|
26
|
+
while not stop_event.is_set():
|
|
27
|
+
try:
|
|
28
|
+
upstream = req_queue.get()
|
|
29
|
+
if upstream is None:
|
|
30
|
+
continue
|
|
31
|
+
|
|
32
|
+
logger.INFO(f"[LOOP] {name} got {upstream}")
|
|
33
|
+
pub_queue.put(f"{name}-{upstream}")
|
|
34
|
+
except Exception as e:
|
|
35
|
+
logger.ERROR(f"[LOOP] {name} failed: {e}")
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def run_demo(mode):
|
|
39
|
+
task_modes = ["once", "hybrid", "loop"]
|
|
40
|
+
|
|
41
|
+
for task_mode in task_modes:
|
|
42
|
+
logger = LogManager(use_mp=True if mode in ("process", "pool") else False, log_path=r'd:\logs\coordinator')
|
|
43
|
+
print(f"\n===== Running Coordinator Demo: mode = {task_mode} {mode} =====")
|
|
44
|
+
# 初始化 Coordinator
|
|
45
|
+
coor = Coordinator(mode=mode, task_mode=task_mode, max_workers=4)
|
|
46
|
+
coor.bind_share(logger=logger)
|
|
47
|
+
|
|
48
|
+
# 注册任务
|
|
49
|
+
if task_mode == "once":
|
|
50
|
+
coor.submit(1, once_task, 1, 2, 3, 4, task_name="onceA")
|
|
51
|
+
coor.submit(2, once_task, 4, 5, 9, upstream_keys=["from_upstream"], task_name="onceB")
|
|
52
|
+
elif task_mode == "hybrid":
|
|
53
|
+
coor.submit(1, hybrid_task, "H1", 123, task_name="hybridA")
|
|
54
|
+
coor.submit(2, hybrid_task, "H2", upstream_keys=["from_upstream"], task_name="hybridB")
|
|
55
|
+
else: # loop
|
|
56
|
+
coor.submit(1, loop_task, name="L1", task_name="loopA")
|
|
57
|
+
coor.submit(2, loop_task, name="L2", task_name="loopB")
|
|
58
|
+
|
|
59
|
+
# 启动协调器
|
|
60
|
+
coor.start()
|
|
61
|
+
time.sleep(3)
|
|
62
|
+
logger.start()
|
|
63
|
+
# 运行一段时间以观察日志输出
|
|
64
|
+
time.sleep(5)
|
|
65
|
+
# 停止协调器
|
|
66
|
+
coor.stop()
|
|
67
|
+
logger.stop()
|
|
68
|
+
|
|
69
|
+
if __name__ == "__main__":
|
|
70
|
+
run_demo("process")
|
demos/ctpgateway_demo.py
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from multiprocessing import Queue
|
|
4
|
+
|
|
5
|
+
sys.path.append(str(Path(__file__).parent.parent))
|
|
6
|
+
|
|
7
|
+
from logixbase.gateway import ctp
|
|
8
|
+
from logixbase.logger import LogManager
|
|
9
|
+
from logixbase.configer import load_schema
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Test:
|
|
13
|
+
|
|
14
|
+
def __init__(self):
|
|
15
|
+
super().__init__()
|
|
16
|
+
self.q = Queue()
|
|
17
|
+
|
|
18
|
+
def on_tick(self, tick):
|
|
19
|
+
""""""
|
|
20
|
+
if self.q.empty():
|
|
21
|
+
self.q.put(tick)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
if __name__ == "__main__":
|
|
25
|
+
loger = LogManager.get_instance(use_mp="process", log_path=r'd:\logs')
|
|
26
|
+
conn_cfg = load_schema(r'D:\licx\codes\usercfg\odin\account.ini', ctp.CtpConfig)
|
|
27
|
+
callback = Test()
|
|
28
|
+
|
|
29
|
+
gateway = ctp.CtpGateway(conn_cfg, loger)
|
|
30
|
+
gateway.register_callback(callback.on_tick)
|
|
31
|
+
gateway.connect()
|
|
32
|
+
info = gateway.subscribe(["i2509", "MA510", "lu2509", "rb2510"])
|
|
33
|
+
# instruments = spi.qry_instrument()
|
|
34
|
+
# margin = spi.qry_margin_rate("rb2410")
|
|
35
|
+
# comm = spi.qry_commission_rate("rb2410")
|
|
36
|
+
# tick = spi.qry_depth_market_data("rb2410")
|
|
37
|
+
# td_code = spi.qry_trading_code("SHFE")
|
|
38
|
+
|
|
39
|
+
if not callback.q.empty():
|
|
40
|
+
tick = callback.q.get()
|
|
41
|
+
|
|
42
|
+
self = ctp.CtpTickClean()
|
|
43
|
+
for k, v in info.items():
|
|
44
|
+
self.register(k, v)
|
|
45
|
+
tick = self.clean_tick(tick)
|
|
46
|
+
|
|
File without changes
|
demos/demoproj/clear.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
print(123123123)
|
demos/demoproj/main.py
ADDED
demos/demoproj/test.py
ADDED
demos/feeder_demo.py
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
import pandas as pd
|
|
3
|
+
sys.path.append(r'D:\licx\codes\logixbase')
|
|
4
|
+
|
|
5
|
+
from logixbase.feeder import TinysoftFeeder, TinysoftConfig, TQSDKConfig
|
|
6
|
+
from logixbase.configer import load_schema, read_config
|
|
7
|
+
from logixbase.utils import unify_time, DatabaseConfig
|
|
8
|
+
from logixbase.feeder.sqlfeeder import SqlServerFeeder
|
|
9
|
+
from logixbase.feeder.tqfeeder import TqsdkFeeder
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def tinysoft_demo():
|
|
14
|
+
conn_cfg = load_schema(r'D:\licx\codes\usercfg\odin\account.ini', TinysoftConfig)
|
|
15
|
+
self = TinysoftFeeder(conn_cfg)
|
|
16
|
+
self.connect()
|
|
17
|
+
self.all_tradeday("2025-04-01", "2025-04-10", fmt="int", freq="W", day=0)
|
|
18
|
+
# 查询基础信息
|
|
19
|
+
basic_info = self.asset_info("future", "basic")
|
|
20
|
+
basic_info = self.asset_info("etf", "basic")
|
|
21
|
+
basic_info = self.asset_info("stock", "basic")
|
|
22
|
+
basic_info = self.asset_info("index", "basic")
|
|
23
|
+
# 查询期权基础信息
|
|
24
|
+
basic_info = self.asset_info("option", "basic", "2025-04-28")
|
|
25
|
+
#查询期货交易信息
|
|
26
|
+
self.asset_info("future", "trade")
|
|
27
|
+
|
|
28
|
+
self.asset_ticker("future", True)
|
|
29
|
+
self.asset_ticker("etf", True)
|
|
30
|
+
self.asset_ticker("stock", True)
|
|
31
|
+
self.asset_ticker("index", True)
|
|
32
|
+
self.asset_ticker("option", True)
|
|
33
|
+
self.option_underlying()
|
|
34
|
+
self.option_ticker_spec("20250402", "M")
|
|
35
|
+
|
|
36
|
+
self.asset_quote("future", "2025-04-02", "2025-04-02", interval="60m", ticker=["CZCE.MA.2505"])
|
|
37
|
+
self.asset_quote("stock", "2025-04-02", "2025-04-02", interval="60m", ticker=["SZSE.000001"])
|
|
38
|
+
self.asset_quote("ETF", "2025-04-02", "2025-04-02", interval="60m", ticker=["SZSE.159003"])
|
|
39
|
+
self.asset_quote("index", "2025-04-02", "2025-04-02", interval="60m", ticker=["SSE.SH000001"])
|
|
40
|
+
self.asset_quote("option", start="2015-03-02", end="2015-03-12", interval="60m", ticker=["SSE.OP10000002"])
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def sql_demo():
|
|
44
|
+
conn_cfg = load_schema(r'D:\licx\codes\usercfg\odin\db_cfg.ini', DatabaseConfig)
|
|
45
|
+
self = SqlServerFeeder(conn_cfg)
|
|
46
|
+
self.connect()
|
|
47
|
+
# self.all_trade_day("2025-04-01", "2025-04-10", fmt="int", freq="W", day=0)
|
|
48
|
+
# self.trade_time(["RB", "IF", "sc"], call_auction=True)
|
|
49
|
+
# self.asset_ticker("stock", True)
|
|
50
|
+
|
|
51
|
+
# self.asset_info("future", "basic")
|
|
52
|
+
# self.asset_info("future", "basic", product=["IF"])
|
|
53
|
+
# self.asset_info("future", "basic", ticker=["CFFEX.IF.2505", "CZCE.MA.HOT", "SHFE.rb"])
|
|
54
|
+
self.asset_info("future", "TRADE", ticker=["CFFEX.IF.2505", "CZCE.MA.HOT", "SHFE.rb"], use_schema=True)
|
|
55
|
+
# info = self.asset_info("future", "basic", use_schema=True)
|
|
56
|
+
# info = self.asset_info("future", "basic", product=["CFFEX.IF"], use_schema=True)
|
|
57
|
+
info = self.asset_info("future", "basic", ticker=["CFFEX.IF.2505", "CZCE.MA.HOT", "SHFE.rb"], use_schema=True)
|
|
58
|
+
info = self.asset_info("stock", "basic", ticker=['SSE.SH600520', 'SZSE.002520', 'SSE.STK.603009'], use_schema=True)
|
|
59
|
+
info = self.asset_info("etf", "basic", ticker=['SSE.ETF.159001', 'SZSE.ETF.510050'], use_schema=True)
|
|
60
|
+
info = self.asset_info("index", "basic", ticker=["SSE.IDX.SH000001", "SZSE.IDX.SZ399001"], use_schema=True)
|
|
61
|
+
|
|
62
|
+
# self.asset_main_ticker("future", "2025-04-01", "2025-04-10")
|
|
63
|
+
# self.asset_main_ticker("future", "2025-04-01", "2025-04-10", ['CFFEX.IF.2505', 'CZCE.MA.HOT', 'SHFE.rb.00', 'DCE.i'])
|
|
64
|
+
|
|
65
|
+
# self.asset_quote("future", "20250401", "20250402", "daily")
|
|
66
|
+
# self.asset_quote("future", "20250401", "20250402", "day")
|
|
67
|
+
self.asset_quote("future", "20250401", "20250402", "daily", ticker=['CFFEX.IF.2505', 'CZCE.MA.HOT', 'CZCE.MA.01', 'SHFE.rb.00', 'DCE.i'])
|
|
68
|
+
# self.asset_quote("future", "20250401", "20250402", "30min")
|
|
69
|
+
# self.asset_quote("future", "20250401", "20250402", "30min")
|
|
70
|
+
self.asset_quote("future", "20250401", "20250430", "m30", ticker=['CFFEX.IF.2505', 'CZCE.MA.HOT', 'CZCE.MA.01', 'SHFE.rb.00', 'DCE.i'])
|
|
71
|
+
self.asset_quote("future", "20250401", "20250430", "m35", ticker=['CFFEX.IF.2505', 'CZCE.MA.HOT', 'CZCE.MA.01', 'SHFE.rb.00', 'DCE.i'])
|
|
72
|
+
# self.asset_quote("future", "20250401", "20250402", "30m", product=["SHFE.rb", "CZZE.MA", "DCE.i.00"])
|
|
73
|
+
# self.asset_quote("future", "20250401", "20250402", "30min", ticker=["SHFE.rb2505", "CZCE.MA509", "DCE.i2509"])
|
|
74
|
+
|
|
75
|
+
# self.asset_quote("stock", "20250401", "20250402", "day")
|
|
76
|
+
# self.asset_quote("stock", "20250401", "20250402", "daily", product=["SZSE.000001", "SSE.600520"])
|
|
77
|
+
self.asset_quote("stock", "20250401", "20250402", "daily", ticker=["SZSE.000001", "SSE.SH600520"])
|
|
78
|
+
self.asset_quote("stock", "20250401", "20250402", "60min", ticker=["SZSE.000001", "SSE.SH600520"])
|
|
79
|
+
# self.asset_quote("stock", "20250401", "20250402", "m60", product=["SZSE.000001", "SSE.SH600520"])
|
|
80
|
+
|
|
81
|
+
# self.asset_quote("index", "20250401", "20250402", "day")
|
|
82
|
+
# self.asset_quote("index", "20250401", "20250402", "daily", product=["SSE.SH000001"])
|
|
83
|
+
# self.asset_quote("index", "20250401", "20250402", "daily", ticker=["SSE.SH000001"])
|
|
84
|
+
# self.asset_quote("index", "20250401", "20250402", "30min", ticker=["SSE.SH000001"])
|
|
85
|
+
# self.asset_quote("index", "20250401", "20250402", "m30", product=["SSE.SH000001"])
|
|
86
|
+
|
|
87
|
+
# self.asset_quote("etf", "20250401", "20250402", "day")
|
|
88
|
+
# self.asset_quote("etf", "20250401", "20250402", "daily", product=["SZSE.159660", "SZSE.SZ159662"])
|
|
89
|
+
# self.asset_quote("etf", "20250401", "20250402", "daily", ticker=["SZSE.159660", "SZSE.SZ159662"])
|
|
90
|
+
# self.asset_quote("etf", "20250401", "20250402", "30min", ticker=["SZSE.159660", "SZSE.SZ159662"])
|
|
91
|
+
# self.asset_quote("etf", "20250401", "20250402", "m30", product=["SZSE。159660", "SZSE.SZ159662"])
|
|
92
|
+
|
|
93
|
+
# self.asset_coef_adj("future", ["RB", "I"], "20250401", "20250430")
|
|
94
|
+
|
|
95
|
+
quote = self.asset_quote("future", "20250401", "20250430", "m35", ["SHFE.rb", "CFFEX.IF", "INE.sc", "CZCE.MA","INE.lu.00"], use_schema=True)
|
|
96
|
+
quote = self.asset_quote("index", "20250401", "20250430", "m35", ["SSE.IDX.SH000001"], use_schema=True)
|
|
97
|
+
quote = self.asset_quote("stock", "20250401", "20250430", "m25", ["SZSE.000001", "SSE.SH600520"], use_schema=True)
|
|
98
|
+
quote = self.asset_quote("etf", "20250401", "20250430", "m25", ["SZSE.159660", "SZSE.SZ159662"], use_schema=True)
|
|
99
|
+
quote1 = self.asset_quote("stock", "20250401", "20250430", "m18", ["SZSE.000001", "SZSE.SH600520"], use_schema=True)
|
|
100
|
+
|
|
101
|
+
merged = self.merge_schema(quote, quote1, is_bar=True)
|
|
102
|
+
quote_df = self.parse_bar_schema(merged)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def tqsdk_demo():
|
|
106
|
+
conn_cfg = load_schema(r'D:\licx\codes\usercfg\odin\account.ini', TQSDKConfig)
|
|
107
|
+
self = TqsdkFeeder(conn_cfg['tqsdk'])
|
|
108
|
+
self.connect()
|
|
109
|
+
|
|
110
|
+
instrument = self.asset_ticker("future")
|
|
111
|
+
info = self.asset_info("future", "basic", ticker=["CFFEX.IF.2505", "CZCE.MA.2510", "SHFE.rb.2510"])
|
|
112
|
+
quote = self.asset_quote("future", start, end, interval, ticker=["CFFEX.IF.2505", "CZCE.MA.2510"])
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
if __name__ == '__main__':
|
|
116
|
+
# tinysoft_demo()
|
|
117
|
+
# sql_demo()
|
|
118
|
+
start = "20250401"
|
|
119
|
+
end = "20250430"
|
|
120
|
+
interval = "60min"
|
demos/logger_demo.py
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import time
|
|
2
|
+
import threading
|
|
3
|
+
import multiprocessing
|
|
4
|
+
import sys
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
sys.path.append(str(Path(__file__).parent.parent))
|
|
9
|
+
# 导入 Logger 模块
|
|
10
|
+
from logixbase.logger import LogManager, auto_log
|
|
11
|
+
|
|
12
|
+
# ---------------------------
|
|
13
|
+
# 示例:使用装饰器自动记录函数执行日志
|
|
14
|
+
# ---------------------------
|
|
15
|
+
@auto_log
|
|
16
|
+
def sample_function(x, y):
|
|
17
|
+
"""
|
|
18
|
+
示例函数,用于演示 @auto_log 装饰器的使用。
|
|
19
|
+
该装饰器会自动记录函数开始、结束及执行时长信息。
|
|
20
|
+
"""
|
|
21
|
+
time.sleep(1) # 模拟耗时操作
|
|
22
|
+
return x + y
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
# ---------------------------
|
|
26
|
+
# 示例:单线程日志记录
|
|
27
|
+
# ---------------------------
|
|
28
|
+
def demo_single_thread_logging():
|
|
29
|
+
"""演示在单线程环境下记录日志"""
|
|
30
|
+
logger = LogManager.get_instance(use_mp=False, log_path=r'd:\logs')
|
|
31
|
+
logger.INFO("【Single Thread Demo】开始单线程日志记录。")
|
|
32
|
+
for i in range(3):
|
|
33
|
+
logger.DEBUG(f"单线程记录调试信息 {i}")
|
|
34
|
+
time.sleep(0.3)
|
|
35
|
+
logger.INFO("【Single Thread Demo】单线程日志记录结束。")
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
# ---------------------------
|
|
39
|
+
# 示例:多线程日志记录
|
|
40
|
+
# ---------------------------
|
|
41
|
+
def demo_multithread_logging():
|
|
42
|
+
"""演示在多线程环境下记录日志"""
|
|
43
|
+
logger = LogManager.get_instance(use_mp=False, log_path=r'd:\logs')
|
|
44
|
+
logger.INFO("【Multithread Demo】开始多线程日志记录。")
|
|
45
|
+
|
|
46
|
+
def worker(thread_id):
|
|
47
|
+
for i in range(3):
|
|
48
|
+
logger.DEBUG(f"线程 {thread_id} 记录调试信息 {i}")
|
|
49
|
+
time.sleep(0.3)
|
|
50
|
+
|
|
51
|
+
threads = [threading.Thread(target=worker, args=(i,)) for i in range(3)]
|
|
52
|
+
for t in threads:
|
|
53
|
+
t.start()
|
|
54
|
+
for t in threads:
|
|
55
|
+
t.join()
|
|
56
|
+
logger.INFO("【Multithread Demo】多线程日志记录结束。")
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
# ---------------------------
|
|
60
|
+
# 示例:多进程日志记录(类场景)
|
|
61
|
+
# ---------------------------
|
|
62
|
+
def process_worker(logger, proc_id):
|
|
63
|
+
"""模拟多进程日志记录"""
|
|
64
|
+
for i in range(3):
|
|
65
|
+
# 将日志消息放入共享队列,由主进程统一写入日志
|
|
66
|
+
logger.INFO(f"[子进程 {proc_id}] 记录日志消息 {i}")
|
|
67
|
+
time.sleep(0.3)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class MultiprocessLogger:
|
|
71
|
+
def __init__(self, use_mp=True):
|
|
72
|
+
# 每次初始化时都动态创建 LogManager 实例,确保 use_mp 参数正确
|
|
73
|
+
self.logger = LogManager.get_instance(use_mp=use_mp, log_path=r'd:\logs')
|
|
74
|
+
|
|
75
|
+
# 确保只有在多进程模式下才尝试访问 mp_queue
|
|
76
|
+
if self.logger.use_mp:
|
|
77
|
+
self.shared_queue = self.logger.log_writer.log_queue # 获取共享队列
|
|
78
|
+
else:
|
|
79
|
+
self.shared_queue = None
|
|
80
|
+
|
|
81
|
+
self.processes = []
|
|
82
|
+
|
|
83
|
+
def demo_multiprocess_logging(self):
|
|
84
|
+
"""演示多进程环境下记录日志"""
|
|
85
|
+
if self.shared_queue is None:
|
|
86
|
+
print("未启用多进程模式,无法演示多进程日志记录。")
|
|
87
|
+
return
|
|
88
|
+
|
|
89
|
+
logger = self.logger
|
|
90
|
+
logger.INFO("【Multiprocess Demo】开始多进程日志记录(共享队列方式)。")
|
|
91
|
+
|
|
92
|
+
# 启动多个子进程
|
|
93
|
+
for pid in range(2): # 启动 2 个子进程
|
|
94
|
+
# p = multiprocessing.Process(target=process_worker, args=(self.shared_queue, pid))
|
|
95
|
+
p = multiprocessing.Process(target=process_worker, args=(self.logger, pid))
|
|
96
|
+
self.processes.append(p)
|
|
97
|
+
p.start()
|
|
98
|
+
self.logger.start()
|
|
99
|
+
# 等待所有子进程执行完毕
|
|
100
|
+
for p in self.processes:
|
|
101
|
+
p.join()
|
|
102
|
+
logger.INFO("【Multiprocess Demo】多进程日志记录结束。")
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
# ---------------------------
|
|
106
|
+
# 演示 Logger 模块常用用法
|
|
107
|
+
# ---------------------------
|
|
108
|
+
def demo_logger_usage(use_mp=False):
|
|
109
|
+
"""综合演示 Logger 的常用用法,包括直接日志调用、装饰器、以及多线程、多进程场景"""
|
|
110
|
+
if use_mp:
|
|
111
|
+
# 多进程模式
|
|
112
|
+
print("\n执行多进程版本的日志记录...")
|
|
113
|
+
mp_logger = MultiprocessLogger(use_mp=True)
|
|
114
|
+
mp_logger.demo_multiprocess_logging()
|
|
115
|
+
else:
|
|
116
|
+
# 单进程模式
|
|
117
|
+
print("\n执行单进程版本的日志记录...")
|
|
118
|
+
# 单线程模式
|
|
119
|
+
logger_single_thread = LogManager.get_instance(use_mp=False, log_path=r'd:\logs')
|
|
120
|
+
logger_single_thread.INFO("【Single Thread Demo】开始演示单线程日志记录。")
|
|
121
|
+
demo_single_thread_logging()
|
|
122
|
+
|
|
123
|
+
# 多线程模式
|
|
124
|
+
logger_multithread = LogManager.get_instance(use_mp=False, log_path=r'd:\logs')
|
|
125
|
+
logger_multithread.INFO("【Multithread Demo】开始演示多线程日志记录。")
|
|
126
|
+
demo_multithread_logging()
|
|
127
|
+
|
|
128
|
+
# 演示装饰器:调用被 @auto_log 装饰的 sample_function
|
|
129
|
+
result = sample_function(5, 7)
|
|
130
|
+
LogManager.get_instance().INFO(f"sample_function(5, 7) 返回结果:{result}")
|
|
131
|
+
|
|
132
|
+
# 等待一段时间确保所有异步日志都写入(可根据实际情况调整时间)
|
|
133
|
+
time.sleep(5)
|
|
134
|
+
LogManager.get_instance().stop()
|
|
135
|
+
print("Logger demo 执行完毕,日志已写入至日志目录。")
|
|
136
|
+
log_path = LogManager.get_instance().config.get("log_path", "./logs")
|
|
137
|
+
print(f"请查看日志文件(目录:{log_path})以验证输出。")
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
# ---------------------------
|
|
141
|
+
# Dashboard 用法说明
|
|
142
|
+
# ---------------------------
|
|
143
|
+
def demo_dashboard_usage():
|
|
144
|
+
print("\n--------------------------------------")
|
|
145
|
+
print("Dashboard 演示:")
|
|
146
|
+
print("请打开终端,执行以下命令启动 Dashboard:")
|
|
147
|
+
print(" uvicorn dashboard.main:app --reload")
|
|
148
|
+
print("启动后,在浏览器中访问 http://127.0.0.1:8000 即可查看实时日志查询界面。")
|
|
149
|
+
print("--------------------------------------\n")
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
# ---------------------------
|
|
153
|
+
# 主入口
|
|
154
|
+
# ---------------------------
|
|
155
|
+
if __name__ == '__main__':
|
|
156
|
+
# 控制是否使用多进程
|
|
157
|
+
demo_logger_usage(use_mp=True) # 使用多进程版本
|
|
158
|
+
# demo_logger_usage(use_mp=False) # 使用单进程版本
|
|
159
|
+
# demo_dashboard_usage()
|
|
160
|
+
print("Demo 演示完成。")
|