akquant 0.1.0__cp39-abi3-win_amd64.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.

Potentially problematic release.


This version of akquant might be problematic. Click here for more details.

akquant/log.py ADDED
@@ -0,0 +1,135 @@
1
+ import logging
2
+ import sys
3
+ from typing import Optional, Union
4
+
5
+ # Default format: Time | Level | Message
6
+ DEFAULT_FORMAT = "%(asctime)s | %(levelname)s | %(message)s"
7
+ DATE_FORMAT = "%Y-%m-%d %H:%M:%S"
8
+
9
+
10
+ class Logger:
11
+ r"""
12
+ akquant 日志封装
13
+
14
+ :description: 提供控制台与文件日志的快捷配置
15
+ """
16
+
17
+ _instance = None
18
+
19
+ def __init__(self):
20
+ self._logger = logging.getLogger("akquant")
21
+ self._logger.setLevel(logging.INFO)
22
+ self._handlers = {} # key -> handler
23
+
24
+ # Add default console handler if not present
25
+ if not self._logger.handlers:
26
+ self.enable_console()
27
+
28
+ @classmethod
29
+ def get_logger(cls):
30
+ if cls._instance is None:
31
+ cls._instance = Logger()
32
+ return cls._instance._logger
33
+
34
+ def set_level(self, level: Union[str, int]):
35
+ r"""
36
+ 设置日志等级
37
+
38
+ :param level: 日志等级字符串或整数 (DEBUG/INFO/WARNING/ERROR/CRITICAL)
39
+ :type level: str | int
40
+ """
41
+ self._logger.setLevel(level)
42
+
43
+ def enable_console(self, format_str: str = DEFAULT_FORMAT):
44
+ r"""
45
+ 启用控制台日志
46
+
47
+ :param format_str: 日志格式字符串
48
+ :type format_str: str
49
+ """
50
+ if "console" in self._handlers:
51
+ return
52
+
53
+ handler = logging.StreamHandler(sys.stdout)
54
+ handler.setFormatter(logging.Formatter(format_str, datefmt=DATE_FORMAT))
55
+ self._logger.addHandler(handler)
56
+ self._handlers["console"] = handler
57
+
58
+ def disable_console(self):
59
+ r"""
60
+ 禁用控制台日志
61
+ """
62
+ if "console" in self._handlers:
63
+ self._logger.removeHandler(self._handlers["console"])
64
+ del self._handlers["console"]
65
+
66
+ def enable_file(
67
+ self, filename: str, format_str: str = DEFAULT_FORMAT, mode: str = "a"
68
+ ):
69
+ r"""
70
+ 启用文件日志
71
+
72
+ :param filename: 日志文件路径
73
+ :type filename: str
74
+ :param format_str: 日志格式字符串
75
+ :type format_str: str
76
+ :param mode: 文件打开模式 ('a' 追加 或 'w' 覆写)
77
+ :type mode: str
78
+ """
79
+ # Remove existing file handler if path matches (simple check)
80
+ key = f"file_{filename}"
81
+ if key in self._handlers:
82
+ return
83
+
84
+ handler = logging.FileHandler(filename, mode=mode, encoding="utf-8")
85
+ handler.setFormatter(logging.Formatter(format_str, datefmt=DATE_FORMAT))
86
+ self._logger.addHandler(handler)
87
+ self._handlers[key] = handler
88
+
89
+
90
+ # Global helper functions
91
+ def get_logger():
92
+ r"""
93
+ 获取全局 logger 实例
94
+
95
+ :return: 已初始化的 logger
96
+ :rtype: logging.Logger
97
+ """
98
+ return Logger.get_logger()
99
+
100
+
101
+ def set_log_level(level: Union[str, int]):
102
+ r"""
103
+ 设置全局日志等级
104
+
105
+ :param level: 日志等级字符串或整数
106
+ :type level: str | int
107
+ """
108
+ Logger.get_logger().setLevel(level)
109
+
110
+
111
+ def register_logger(
112
+ filename: Optional[str] = None, console: bool = True, level: str = "INFO"
113
+ ):
114
+ r"""
115
+ 日志一体化配置
116
+
117
+ :param filename: 日志文件路径,提供则写入文件
118
+ :type filename: str, optional
119
+ :param console: 是否输出到控制台
120
+ :type console: bool
121
+ :param level: 日志等级 ("DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL")
122
+ :type level: str
123
+ """
124
+ logger_manager = Logger._instance or Logger()
125
+ Logger._instance = logger_manager
126
+
127
+ logger_manager.set_level(level.upper())
128
+
129
+ if console:
130
+ logger_manager.enable_console()
131
+ else:
132
+ logger_manager.disable_console()
133
+
134
+ if filename:
135
+ logger_manager.enable_file(filename)
akquant/sizer.py ADDED
@@ -0,0 +1,82 @@
1
+ from abc import ABC, abstractmethod
2
+ from typing import TYPE_CHECKING
3
+
4
+ if TYPE_CHECKING:
5
+ from .akquant import StrategyContext
6
+
7
+
8
+ class Sizer(ABC):
9
+ """
10
+ 仓位管理基类 (Sizer Base Class)
11
+ 用于计算下单数量
12
+ """
13
+
14
+ @abstractmethod
15
+ def get_size(
16
+ self, price: float, cash: float, context: "StrategyContext", symbol: str
17
+ ) -> float:
18
+ """
19
+ 计算下单数量
20
+
21
+ Args:
22
+ price (float): 当前价格
23
+ cash (float): 当前可用资金
24
+ context (StrategyContext): 策略上下文
25
+ symbol (str): 标的代码
26
+
27
+ Returns:
28
+ float: 下单数量
29
+ """
30
+ pass
31
+
32
+
33
+ class FixedSize(Sizer):
34
+ """
35
+ 固定数量 Sizer
36
+ 每次交易固定数量
37
+ """
38
+
39
+ def __init__(self, size: float = 100.0):
40
+ self.size = size
41
+
42
+ def get_size(
43
+ self, price: float, cash: float, context: "StrategyContext", symbol: str
44
+ ) -> float:
45
+ return self.size
46
+
47
+
48
+ class PercentSizer(Sizer):
49
+ """
50
+ 百分比 Sizer
51
+ 使用当前资金的一定百分比买入
52
+ """
53
+
54
+ def __init__(self, percents: float = 10.0):
55
+ """
56
+ Args:
57
+ percents (float): 资金百分比 (0-100)
58
+ """
59
+ self.percents = percents
60
+
61
+ def get_size(
62
+ self, price: float, cash: float, context: "StrategyContext", symbol: str
63
+ ) -> float:
64
+ if price <= 0:
65
+ return 0.0
66
+
67
+ target_cash = cash * (self.percents / 100.0)
68
+ return int(target_cash / price)
69
+
70
+
71
+ class AllInSizer(Sizer):
72
+ """
73
+ 全仓 Sizer
74
+ 使用所有可用资金买入
75
+ """
76
+
77
+ def get_size(
78
+ self, price: float, cash: float, context: "StrategyContext", symbol: str
79
+ ) -> float:
80
+ if price <= 0:
81
+ return 0.0
82
+ return int(cash / price)