quant1x-trader 0.0.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.
@@ -0,0 +1,43 @@
1
+ Metadata-Version: 2.4
2
+ Name: quant1x-trader
3
+ Version: 0.0.0
4
+ Summary: Quant1X programmatic automated trading
5
+ Author-email: Wang Feng <wangfengxy@sina.cn>
6
+ License: MIT
7
+ Project-URL: Homepage, https://gitee.com/quant1x/trader
8
+ Keywords: quant1x,auto,trader
9
+ Classifier: Development Status :: 2 - Pre-Alpha
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Natural Language :: English
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.8
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Requires-Python: >=3.8
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Requires-Dist: future~=1.0.0
23
+ Requires-Dist: numpy~=2.3.0
24
+ Requires-Dist: pandas~=2.3.0
25
+ Requires-Dist: PyYAML~=6.0.1
26
+ Requires-Dist: pywin32==311
27
+ Requires-Dist: uvicorn~=0.29.0
28
+ Requires-Dist: fastapi~=0.110.2
29
+ Requires-Dist: path~=16.14.0
30
+ Requires-Dist: requests~=2.32.0
31
+ Requires-Dist: loguru~=0.7.2
32
+ Requires-Dist: quant1x-xtquant~=2025.5.26
33
+ Requires-Dist: quant1x-base~=0.6.29
34
+ Requires-Dist: aiohttp~=3.12.15
35
+ Requires-Dist: sanic~=23.12.1
36
+ Requires-Dist: python-multipart~=0.0.19
37
+ Requires-Dist: APScheduler~=3.10.4
38
+ Dynamic: license-file
39
+
40
+ # trader
41
+
42
+ #### 介绍
43
+ python实现的自动化交易员
@@ -0,0 +1,14 @@
1
+ quant1x_trader-0.0.0.dist-info/licenses/LICENSE,sha256=QGbg9vBu92X93RlRr7rDfQvc632ykqWzhC1iWs17OC0,1087
2
+ trader1x/__init__.py,sha256=tFXhZX139csbXPeqDgknKRFQC3cTHcWiWZDeY1c7E7o,103
3
+ trader1x/config.py,sha256=Lln9Ze8teUQesLV9bn_vQSt0ItcAyIT8YF1wQTdpTUo,8791
4
+ trader1x/context.py,sha256=YKxZbNsF8RAMbBWZPlPWz21K7lkWKlSMM19_tD8lAgw,7717
5
+ trader1x/log4py.py,sha256=HNdS2tv_mKEwm2FljcCz9vRAaefGjsQX4xpyeDTN-Gw,1159
6
+ trader1x/proxy.py,sha256=K9zOs_BDcM0NjG9A1bjdquer9-zB8bQHDRCmxqdurOc,18268
7
+ trader1x/thinktrader.py,sha256=w6R99MoSihqnHljI7ps9ijU3bM_HDy9nmvqTSc5WSYQ,19322
8
+ trader1x/utils.py,sha256=pmY20CM3-JO0kfkmrUCpfFp5wTLDQYEy1SfgNIMNytc,1323
9
+ trader1x/win32serviceutil.py,sha256=jieIIyTdGEM3oNW4t5oKcG1Uf5MK9NC9tyTskTzUDD8,38933
10
+ quant1x_trader-0.0.0.dist-info/METADATA,sha256=qNCpWX6NaNmVJX81lPnThmMaL7ZsxLGEgzsYX7u_HDM,1452
11
+ quant1x_trader-0.0.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
12
+ quant1x_trader-0.0.0.dist-info/entry_points.txt,sha256=KaWVu2VzttfRIQRrZ9DxKj8etOEtnKl8REILAwditp4,58
13
+ quant1x_trader-0.0.0.dist-info/top_level.txt,sha256=J1TOgUDUKoWldrXZ0qIdRCfbLTcTsD53UYzHXhsAZdM,9
14
+ quant1x_trader-0.0.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ quant1x-qmt-proxy = trader1x.proxy:main
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 王布衣
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ trader1x
trader1x/__init__.py ADDED
@@ -0,0 +1,5 @@
1
+ # -*- coding: UTF-8 -*-
2
+
3
+ __author__ = 'WangFeng'
4
+
5
+ # from .logger import logger, quant1x_data_path
trader1x/config.py ADDED
@@ -0,0 +1,251 @@
1
+ # -*- coding: UTF-8 -*-
2
+ import os
3
+ import sys
4
+ import warnings
5
+ from dataclasses import dataclass, field
6
+
7
+ import q1x.base
8
+ import yaml
9
+ from q1x.base import TradingSession
10
+
11
+ from trader1x import utils
12
+ from trader1x.log4py import logger
13
+
14
+ warnings.filterwarnings('ignore')
15
+
16
+
17
+ def list_default_factory():
18
+ return []
19
+
20
+
21
+ @dataclass
22
+ class TradeRule:
23
+ """
24
+ 交易规则
25
+ """
26
+ id: int = -1 # 策略ID, -1无效
27
+ auto: bool = False # 是否自动执行
28
+ name: str = None # 策略名称
29
+ flag: str = '' # 订单标识,分早盘,尾盘和盘中
30
+ time: TradingSession = field(default_factory=lambda: TradingSession("09:30:00~11:30:00,13:00:00~14:56:30"))
31
+ weight: int = 0 # 策略权重, 默认0, 由系统自动分配
32
+ total: int = 3 # 订单总数, 默认是3
33
+ fee_max: float = 20000.00 # 可投入资金-最大
34
+ fee_min: float = 10000.00 # 可投入资金-最小
35
+ sectors: list[str] = None # 板块, 策略适用的板块列表, 默认板块为空, 即全部个股
36
+ ignore_margin_trading: bool = True # 剔除两融标的, 默认是剔除
37
+
38
+ def __init__(self, params: dict = None):
39
+ """
40
+ 初始化
41
+ """
42
+ # 先让 dataclass 初始化默认值
43
+ # 手动初始化所有字段
44
+ self.time = TradingSession("09:30:00~11:30:00,13:00:00~14:56:30")
45
+ if params is None:
46
+ return
47
+ for key, value in params.items():
48
+ if not hasattr(self, key):
49
+ continue
50
+ tmp_value = getattr(self, key)
51
+ if isinstance(tmp_value, TradingSession):
52
+ new_value = TradingSession(value)
53
+ setattr(self, key, new_value)
54
+ else:
55
+ setattr(self, key, value)
56
+
57
+ def enable(self) -> bool:
58
+ """
59
+ 是否有效
60
+ :return:
61
+ """
62
+ return self.auto and self.id >= 0
63
+
64
+ def buy_enable(self) -> bool:
65
+ """
66
+ 买入有效
67
+ :return:
68
+ """
69
+ return self.enable() and self.total > 0
70
+
71
+ def sell_enable(self) -> bool:
72
+ """
73
+ 卖出有效
74
+ :return:
75
+ """
76
+ return self.enable()
77
+
78
+ def is_cookie_cutter_for_sell(self) -> bool:
79
+ """
80
+ 是否一刀切卖出
81
+ :return:
82
+ """
83
+ return self.sell_enable() and self.total == 0
84
+
85
+
86
+ @dataclass
87
+ class TraderConfig:
88
+ """
89
+ 配置信息
90
+ """
91
+ # 账号ID
92
+ account_id: str = ''
93
+ # 运行路径
94
+ order_path: str = ''
95
+ # 时间范围 - 早盘策略
96
+ head_time: TradingSession = field(default_factory=lambda: TradingSession("09:27:00~14:57:00"))
97
+ # 时间范围 - 尾盘策略
98
+ tail_time: TradingSession = field(default_factory=lambda: TradingSession("14:45:00~14:59:50"))
99
+ # 时间范围 - 盘中订单
100
+ tick_time: TradingSession = field(default_factory=lambda: TradingSession("09:39:00-14:57:00"))
101
+ # 时间范围 - 持仓卖出
102
+ ask_time: TradingSession = field(default_factory=lambda: TradingSession("09:50:00~14:59:30"))
103
+ # 时间范围 - 撤销订单
104
+ cancel_time: TradingSession = field(default_factory=lambda: TradingSession("09:15:00~09:19:59, 09:30:00~14:56:59"))
105
+ # 时间范围 - 盘后复盘
106
+ review_time: TradingSession = field(default_factory=lambda: TradingSession("00:00:00~08:30:00, 15:01:00~23:59:59"))
107
+ # 买入持仓率, 资金控制阀值
108
+ position_ratio: float = 0.5000
109
+ # 印花税 - 买入, 按照成交金额, 买入0.0%
110
+ stamp_duty_rate_for_buy: float = 0.0000
111
+ # 印花税 - 卖出, 按照成交金额, 卖出0.1%
112
+ stamp_duty_rate_for_sell: float = 0.0010
113
+ # 过户费 - 双向, 按照数量收取, 默认万分之六, 0.06%
114
+ transfer_rate: float = 0.0006
115
+ # 券商佣金 - 双向, 按成交金额计算, 默认万分之二点五, 0.025%
116
+ commission_rate: float = 0.00025
117
+ # 券商佣金最低, 默认5.00
118
+ commission_min: float = 5.00
119
+ # 保留现金
120
+ keep_cash: float = 10000.00
121
+ # tick订单最大金额, 默认20000.00
122
+ tick_order_max_amount: float = 20000.00
123
+ # tick订单最小金额, 默认10000.00
124
+ tick_order_min_amount: float = 10000.00
125
+ # 买入最大金额
126
+ buy_amount_max: float = 250000.00
127
+ # 买入最小金额
128
+ buy_amount_min: float = 1000.00
129
+ # 每策略最多可买股票数量, 这里默认3
130
+ max_stock_quantity_for_strategy: int = 3
131
+ # 自动卖出, 默认为True
132
+ sell_order_auto: bool = False
133
+ # 自动交易head订单, 默认为True
134
+ head_order_auto: bool = False
135
+ # 自动交易tick订单, 默认为True
136
+ tick_order_auto: bool = False
137
+ # 自动交易tail订单, 默认为True
138
+ tail_order_auto: bool = False
139
+
140
+ # 启动了mimiQMT机器的代理服务的监听地址, 默认为回环地址127.0.0.1, 强烈不推荐使用0.0.0.0
141
+ proxy_address: str = q1x.base.lan_address()
142
+ # 代理服务的监听端口, 默认18168
143
+ proxy_port: int = 18168
144
+ # 代理服务默认工作线程数, 默认为cpu核数的二分之一
145
+ proxy_workers: int = q1x.base.max_procs()
146
+ # qmt proxy地址
147
+ proxy_url: str = ""
148
+ # 策略集合
149
+ strategies: list[TradeRule] = list_default_factory
150
+ # 可撤单的交易时段
151
+ cancel: TradingSession = field(
152
+ default_factory=lambda: TradingSession("09:15:00~09:19:59,09:25:00~11:29:59,13:00:00~14:59:59"))
153
+
154
+ def __fix_instance(self):
155
+ """
156
+ 加载后修复
157
+ :return:
158
+ """
159
+ if isinstance(self.ask_time, str):
160
+ ts = TradingSession(self.ask_time)
161
+ if ts.is_valid():
162
+ self.ask_time = ts
163
+ if isinstance(self.cancel_time, str):
164
+ ts = TradingSession(self.cancel_time)
165
+ if ts.is_valid():
166
+ self.cancel_time = ts
167
+ if isinstance(self.tick_time, str):
168
+ ts = TradingSession(self.tick_time)
169
+ if ts.is_valid():
170
+ self.tick_time = ts
171
+
172
+ def __post_init__(self):
173
+ """
174
+ __init__()后调用, 调整类型
175
+ :return:
176
+ """
177
+ self.__fix_instance()
178
+
179
+
180
+ # 全局变量 - 配置
181
+ __global_config = TraderConfig()
182
+
183
+
184
+ def load(config_filename: str = '') -> TraderConfig:
185
+ """
186
+ 加载配置文件
187
+ :return:
188
+ """
189
+ global __global_config
190
+ config = TraderConfig()
191
+ config_filename = config_filename.strip()
192
+ if len(config_filename) == 0:
193
+ config_filename = utils.get_quant1x_config_filename()
194
+ config_filename = os.path.expanduser(config_filename)
195
+ logger.info(config_filename)
196
+ if not os.path.isfile(config_filename):
197
+ logger.error('QMT config {}: 不存在', config_filename)
198
+ sys.exit(utils.errno_config_not_exist)
199
+ try:
200
+ with open(config_filename, 'r', encoding='utf-8') as f:
201
+ result = yaml.load(f, Loader=yaml.FullLoader)
202
+ key_trader = "trader"
203
+ if isinstance(result, dict) and key_trader in result:
204
+ trader = result[key_trader]
205
+ for key, value in trader.items():
206
+ if not hasattr(config, key):
207
+ continue
208
+ tmp_value = getattr(config, key)
209
+ if isinstance(tmp_value, TradingSession):
210
+ new_value = TradingSession(value)
211
+ setattr(config, key, new_value)
212
+ elif tmp_value is list_default_factory:
213
+ if key == 'strategies':
214
+ tmp_list = []
215
+ if isinstance(value, list):
216
+ for d in value:
217
+ rule = TradeRule(d)
218
+ tmp_list.append(rule)
219
+ setattr(config, key, tmp_list)
220
+ elif key == 'account_id':
221
+ setattr(config, 'account_id', str(value))
222
+ elif key == 'top_n':
223
+ setattr(config, 'max_stock_quantity_for_strategy', value)
224
+ else:
225
+ setattr(config, key, value)
226
+ except Exception as e:
227
+ logger.error(f"发生了一个错误:{config_filename}\n错误信息:{e}")
228
+ logger.warning('系统将使用默认配置')
229
+ config = TraderConfig()
230
+ # finally:
231
+ # logger.warning('系统将使用默认配置')
232
+ # 检查重点配置
233
+ if config.account_id == '':
234
+ logger.error('配置缺少账户id')
235
+ sys.exit(utils.errno_not_found_account_id)
236
+ if config.order_path == '':
237
+ logger.error('配置缺少订单路径')
238
+ sys.exit(utils.errno_not_found_order_path)
239
+ __global_config = config
240
+ return config
241
+
242
+
243
+ def get() -> TraderConfig:
244
+ global __global_config
245
+ return __global_config
246
+
247
+
248
+ if __name__ == '__main__':
249
+ filename = '~/.q1x/quant1x.yaml'
250
+ config = load(filename)
251
+ print(config)
trader1x/context.py ADDED
@@ -0,0 +1,260 @@
1
+ # coding=utf-8
2
+ import os
3
+ import time
4
+
5
+ import pandas as pd
6
+ from xtquant import xtdata
7
+ from xtquant.xttype import StockAccount
8
+
9
+ from trader1x import utils
10
+ from trader1x.config import TraderConfig
11
+ from trader1x.log4py import logger
12
+
13
+ # 禁止显示XtQuant的hello信息
14
+ xtdata.enable_hello = False
15
+
16
+ order_buy = 1
17
+ order_sell = 2
18
+ order_junk = 3
19
+ flag_buy = "b"
20
+ flag_sell = "s"
21
+ flag_junk = "j"
22
+
23
+
24
+ class QmtContext(object):
25
+ """
26
+ QMT 上下文
27
+ TODO: 按日期切换数据
28
+ """
29
+ current_date: str # 当前日期
30
+ config_filename: str # 配置文件名
31
+ order_path: str # quant1x系统输出订单的路径
32
+ account_id: str # 账号ID
33
+ t89k_order_file: str # 订单文件
34
+ t89k_flag_ready: str # 订单就绪标志
35
+ t89k_flag_done: str # 订单执行完成标志
36
+ positions_sell_done: str # 持仓卖出状态
37
+ qmt_order_filename: str # qmt系统输出的订单路径
38
+ qmt_order_done: str # qmt系统每日订单刷新完成标志
39
+ qmt_positions_filename: str # qmt持仓
40
+
41
+ def __init__(self, conf: TraderConfig):
42
+ self._config = conf
43
+ self.current_date = time.strftime(utils.kFormatFileDate)
44
+ self.account_id = conf.account_id
45
+ self.order_path = conf.order_path
46
+ self.switch_date()
47
+
48
+ def account(self) -> StockAccount:
49
+ return StockAccount(self.account_id)
50
+
51
+ def sell_is_ready(self) -> bool:
52
+ """
53
+ 卖出条件是否就绪
54
+ :return:
55
+ """
56
+ return self._config.ask_time.is_trading()
57
+
58
+ def sell_is_auto(self) -> bool:
59
+ """
60
+ 卖出操作是否自动一刀切
61
+ :return:
62
+ """
63
+ return self._config.sell_order_auto
64
+
65
+ def head_order_is_ready(self) -> bool:
66
+ """
67
+ 早盘(买入)订单是否准备就绪
68
+ :return:
69
+ """
70
+ if os.path.isfile(self.t89k_flag_ready) and os.path.isfile(self.t89k_order_file):
71
+ return True
72
+ return False
73
+
74
+ def head_order_is_auto(self) -> bool:
75
+ """
76
+ 是否执行 早盘订单的交易
77
+ :return:
78
+ """
79
+ return self._config.head_order_auto
80
+
81
+ def tick_order_is_auto(self) -> bool:
82
+ """
83
+ 是否执行 盘中即时订单的交易
84
+ :return:
85
+ """
86
+ return self._config.tick_order_auto
87
+
88
+ def tail_order_is_auto(self) -> bool:
89
+ """
90
+ 是否执行 尾盘订单的交易
91
+ :return:
92
+ """
93
+ return self._config.tail_order_auto
94
+
95
+ def can_review(self) -> bool:
96
+ """
97
+ 是佛可以复盘
98
+ :return:
99
+ """
100
+ return self._config.review_time.is_trading()
101
+
102
+ def load_head_order(self) -> pd.DataFrame:
103
+ """
104
+ 加载早盘订单
105
+ :return:
106
+ """
107
+ df = pd.read_csv(self.t89k_order_file)
108
+ return df
109
+
110
+ def switch_date(self):
111
+ """
112
+ 重置属性
113
+ :return:
114
+ """
115
+ logger.warning("switch_date...")
116
+ # self.current_date = time.strftime(utils.kFormatFileDate)
117
+ v = xtdata.get_market_last_trade_date('SH')
118
+ local_time = time.localtime(v / 1000)
119
+ trade_date = time.strftime(utils.kFormatFileDate, local_time)
120
+ self.current_date = trade_date
121
+ logger.warning("switch_date...{}", self.current_date)
122
+ flag = 'head'
123
+ self.t89k_flag_ready = os.path.join(self.order_path, f'{self.current_date}-{flag}.ready')
124
+ self.t89k_flag_done = os.path.join(self.order_path, f'{self.current_date}-{flag}-{self.account_id}.done')
125
+ self.t89k_order_file = os.path.join(self.order_path, f'{self.current_date}-{flag}.csv')
126
+ self.positions_sell_done = os.path.join(self.order_path, f'{self.current_date}-sell-{self.account_id}.done')
127
+ # qmt订单文件
128
+ self.qmt_order_filename = os.path.join(self.order_path, f'{self.account_id}-orders.csv')
129
+ self.qmt_order_done = os.path.join(self.order_path, f'{self.account_id}-orders-{self.current_date}.done')
130
+ # qmt持仓文件
131
+ self.qmt_positions_filename = os.path.join(self.order_path, f'{self.account_id}-positions.csv')
132
+
133
+ def orders_has_refreshed(self) -> bool:
134
+ """
135
+ 当日订单是否已经刷新完成
136
+ :return:
137
+ """
138
+ return self.__filelock(self.qmt_order_done)
139
+
140
+ def push_orders_refreshed(self):
141
+ """
142
+ 标注订单刷新已完成
143
+ :return:
144
+ """
145
+ self._push_local_message(self.qmt_order_done)
146
+
147
+ def push_head_order_buy_completed(self):
148
+ """
149
+ 买入操作完成
150
+ :return:
151
+ """
152
+ self._push_local_message(self.t89k_flag_done)
153
+ logger.info('订单买入操作完成')
154
+
155
+ def head_order_buy_is_finished(self) -> bool:
156
+ """
157
+ 早盘订单是否完成
158
+ :return:
159
+ """
160
+ return os.path.isfile(self.t89k_flag_done)
161
+
162
+ def push_positions_sell_completed(self):
163
+ """
164
+ 标记卖出操作完成
165
+ :return:
166
+ """
167
+ self._push_local_message(self.positions_sell_done)
168
+
169
+ def positions_sell_finished(self):
170
+ """
171
+ 卖出是否操作完成
172
+ :return:
173
+ """
174
+ return os.path.isfile(self.positions_sell_done)
175
+
176
+ def check_buy_order_done_status(self, code: str) -> bool:
177
+ """
178
+ 检查买入订单执行完成状态
179
+ :return:
180
+ """
181
+ flag = self.get_order_flag(code, order_buy)
182
+ return os.path.exists(flag)
183
+
184
+ def push_buy_order_done_status(self, code: str):
185
+ """
186
+ 推送买入订单完成状态
187
+ :param code:
188
+ :return:
189
+ """
190
+ flag = self.get_order_flag(code, order_buy)
191
+ self._push_local_message(flag)
192
+
193
+ def _push_local_message(self, filename: str):
194
+ """
195
+ 推送消息
196
+ :param filename:
197
+ :return:
198
+ """
199
+ with open(filename, 'w') as done_file:
200
+ pass
201
+
202
+ def get_order_flag(self, code: str, type: int) -> str:
203
+ """
204
+ 获取订单标识
205
+ :param self:
206
+ :param code:
207
+ :param type: 1-b(buy),2-s(ell),3-j(unk)
208
+ :return:
209
+ """
210
+ today = time.strftime(utils.kFormatFileDate)
211
+ if type == order_buy:
212
+ order_flag = flag_buy
213
+ elif type == order_sell:
214
+ order_flag = flag_sell
215
+ else:
216
+ order_flag = flag_junk
217
+ order_flag_path = self.order_path + "/var/" + today
218
+ q1x_base.mkdirs(order_flag_path)
219
+ stock_order_flag = os.path.join(order_flag_path, f'{today}-{self.account_id}-{code}-{order_flag}.done')
220
+ return stock_order_flag
221
+
222
+ def fix_security_code(self, symbol: str) -> str:
223
+ """
224
+ 调整证券代码
225
+ :param symbol:
226
+ :return:
227
+ """
228
+ security_code = ''
229
+ if len(symbol) == 6:
230
+ flag = self.get_security_type(symbol)
231
+ security_code = f'{symbol}.{flag}'
232
+ elif len(symbol) == 8 and symbol[:2] in ["sh", "sz", "SH", "SZ"]:
233
+ security_code = symbol[2:] + '.' + symbol[:2].upper()
234
+ else:
235
+ raise utils.errBadSymbol
236
+ return security_code
237
+
238
+ def get_security_type(self, symbol: str) -> str:
239
+ """
240
+ 获取股票市场标识
241
+ :param symbol: 代码
242
+ :return:
243
+ """
244
+ if len(symbol) != 6:
245
+ raise utils.errBadSymbol
246
+ code_head = symbol[:2]
247
+ if code_head in ["00", "30"]:
248
+ return "SZ"
249
+ if code_head in ["60", "68"]: # 688XXX科创板
250
+ return "SH"
251
+ if code_head in ["510"]:
252
+ return "SH"
253
+ raise utils.errBadSymbol
254
+
255
+ def __filelock(self, filename: str) -> bool:
256
+ """
257
+ 文件锁状态
258
+ :return:
259
+ """
260
+ return os.path.isfile(filename)
trader1x/log4py.py ADDED
@@ -0,0 +1,36 @@
1
+ # -*- coding: UTF-8 -*-
2
+ import os
3
+ import sys
4
+
5
+ import yaml
6
+ from loguru import logger as __logger
7
+ from q1x.base import file, application
8
+
9
+ from trader1x import utils
10
+
11
+ # 获取默认的配置文件路径
12
+ config_filename = utils.get_quant1x_config_filename()
13
+ # 转换用户路径
14
+ config_filename = os.path.expanduser(config_filename)
15
+ # 检查配置文件是否存在
16
+ if not os.path.isfile(config_filename):
17
+ __logger.error('QMT config {}: 不存在', config_filename)
18
+ sys.exit(utils.errno_config_not_exist)
19
+
20
+ try:
21
+ with open(config_filename, 'r', encoding='utf-8') as f:
22
+ result = yaml.load(f, Loader=yaml.FullLoader)
23
+ key_basedir = "basedir"
24
+ if isinstance(result, dict) and key_basedir in result:
25
+ quant1x_data_path = result[key_basedir]
26
+ except Exception as e:
27
+ quant1x_data_path = file.homedir()
28
+ quant1x_data_path = os.path.expanduser(quant1x_data_path)
29
+ _, filename, _ = application()
30
+ if filename == 'pythonservice':
31
+ filename = 'proxy'
32
+ __log_file = f"{quant1x_data_path}/logs/{filename}.log"
33
+ # print(__log_file)
34
+ __logger.add(__log_file, encoding="utf-8", rotation="00:00", retention="10 days")
35
+
36
+ logger = __logger