diff --git a/logs/backtest_consumer.log b/logs/backtest_consumer.log new file mode 100644 index 0000000..d631e94 --- /dev/null +++ b/logs/backtest_consumer.log @@ -0,0 +1,207 @@ +[2026-02-25 00:35:42] [DEBUG] [logger.py:77] [MainThread] [QMTLogger] 日志记录器初始化完成: BacktestConsumer +[2026-02-25 00:35:42] [INFO] [logger.py:262] [MainThread] [BacktestConsumer] 初始化完成 +[2026-02-25 00:35:42] [INFO] [logger.py:262] [MainThread] [BacktestConsumer] 消费者ID: backtest-consumer-1 +[2026-02-25 00:35:42] [INFO] [logger.py:262] [MainThread] [BacktestConsumer] 策略列表: 所有策略 +[2026-02-25 00:35:42] [INFO] [logger.py:262] [MainThread] [BacktestConsumer] 单次运行,策略: ['ST_Strategy'] +[2026-02-25 00:35:47] [INFO] [logger.py:262] [MainThread] [BacktestConsumer] 单次运行完成,共处理 0 条消息 +[2026-02-25 00:35:47] [INFO] [logger.py:262] [MainThread] ================================================== +[2026-02-25 00:35:47] [INFO] [logger.py:262] [MainThread] [统计信息] +[2026-02-25 00:35:47] [INFO] [logger.py:262] [MainThread] 运行时间: 4.1 秒 +[2026-02-25 00:35:47] [INFO] [logger.py:262] [MainThread] 接收消息: 0 +[2026-02-25 00:35:47] [INFO] [logger.py:262] [MainThread] 处理成功: 0 +[2026-02-25 00:35:47] [INFO] [logger.py:262] [MainThread] 处理失败: 0 +[2026-02-25 00:35:47] [INFO] [logger.py:262] [MainThread] ================================================== +[2026-02-25 00:38:22] [DEBUG] [logger.py:77] [MainThread] [QMTLogger] 日志记录器初始化完成: BacktestConsumer +[2026-02-25 00:38:22] [INFO] [logger.py:262] [MainThread] [BacktestConsumer] 初始化完成 +[2026-02-25 00:38:22] [INFO] [logger.py:262] [MainThread] [BacktestConsumer] 消费者ID: backtest-consumer-1 +[2026-02-25 00:38:22] [INFO] [logger.py:262] [MainThread] [BacktestConsumer] 策略列表: 所有策略 +[2026-02-25 00:38:22] [INFO] [logger.py:262] [MainThread] [BacktestConsumer] 单次运行,策略: ['ST_Strategy'] +[2026-02-25 00:38:26] [INFO] [logger.py:262] [MainThread] [BacktestConsumer] 单次运行完成,共处理 0 条消息 +[2026-02-25 00:38:26] [INFO] [logger.py:262] [MainThread] ================================================== +[2026-02-25 00:38:26] [INFO] [logger.py:262] [MainThread] [统计信息] +[2026-02-25 00:38:26] [INFO] [logger.py:262] [MainThread] 运行时间: 4.1 秒 +[2026-02-25 00:38:26] [INFO] [logger.py:262] [MainThread] 接收消息: 0 +[2026-02-25 00:38:26] [INFO] [logger.py:262] [MainThread] 处理成功: 0 +[2026-02-25 00:38:26] [INFO] [logger.py:262] [MainThread] 处理失败: 0 +[2026-02-25 00:38:26] [INFO] [logger.py:262] [MainThread] ================================================== +[2026-02-25 00:38:38] [DEBUG] [logger.py:77] [MainThread] [QMTLogger] 日志记录器初始化完成: BacktestConsumer +[2026-02-25 00:38:38] [INFO] [logger.py:262] [MainThread] [BacktestConsumer] 初始化完成 +[2026-02-25 00:38:38] [INFO] [logger.py:262] [MainThread] [BacktestConsumer] 消费者ID: backtest-consumer-1 +[2026-02-25 00:38:38] [INFO] [logger.py:262] [MainThread] [BacktestConsumer] 策略列表: 所有策略 +[2026-02-25 00:38:38] [INFO] [logger.py:262] [MainThread] [BacktestConsumer] 单次运行,策略: ['ST_Strategy'] +[2026-02-25 00:38:42] [INFO] [logger.py:262] [MainThread] [BacktestConsumer] 单次运行完成,共处理 0 条消息 +[2026-02-25 00:38:42] [INFO] [logger.py:262] [MainThread] ================================================== +[2026-02-25 00:38:42] [INFO] [logger.py:262] [MainThread] [统计信息] +[2026-02-25 00:38:42] [INFO] [logger.py:262] [MainThread] 运行时间: 4.1 秒 +[2026-02-25 00:38:42] [INFO] [logger.py:262] [MainThread] 接收消息: 0 +[2026-02-25 00:38:42] [INFO] [logger.py:262] [MainThread] 处理成功: 0 +[2026-02-25 00:38:42] [INFO] [logger.py:262] [MainThread] 处理失败: 0 +[2026-02-25 00:38:42] [INFO] [logger.py:262] [MainThread] ================================================== +[2026-02-25 00:39:29] [DEBUG] [logger.py:77] [MainThread] [QMTLogger] 日志记录器初始化完成: BacktestConsumer +[2026-02-25 00:39:29] [INFO] [logger.py:262] [MainThread] [BacktestConsumer] 初始化完成 +[2026-02-25 00:39:29] [INFO] [logger.py:262] [MainThread] [BacktestConsumer] 消费者ID: backtest-consumer-1 +[2026-02-25 00:39:29] [INFO] [logger.py:262] [MainThread] [BacktestConsumer] 策略列表: 所有策略 +[2026-02-25 00:39:29] [INFO] [logger.py:262] [MainThread] [BacktestConsumer] 单次运行,策略: ['ST_Strategy'] +[2026-02-25 00:39:29] [DEBUG] [logger.py:89] [MainThread] [消息接收] stream=qmt:ST_Strategy:backtest, id=1771950790601-0, data={'strategy_name': 'ST_Strategy', 'stock_code': '603007.SH', 'action': 'BUY', 'price': 5.85, 'total_slots': 5, 'timestamp': '2026-01-05 09:31:00', 'is_backtest': True} +[2026-02-25 00:39:29] [DEBUG] [logger.py:112] [MainThread] [消息解析] strategy=ST_Strategy, code=603007.SH, action=BUY, price=5.85, extra={'total_slots': 5, 'timestamp': '2026-01-05 09:31:00', 'is_backtest': True} +[2026-02-25 00:39:29] [DEBUG] [logger.py:133] [MainThread] [业务校验] type=field_check, strategy=ST_Strategy, result=通过, details={'fields': ['strategy_name', 'stock_code', 'action', 'price', 'total_slots', 'timestamp', 'is_backtest']} +[2026-02-25 00:39:29] [DEBUG] [logger.py:170] [MainThread] [订单执行请求] strategy=ST_Strategy, code=603007.SH, action=BUY, vol=100, price=5.85 +[2026-02-25 00:39:30] [INFO] [logger.py:262] [MainThread] [模拟交易] ST_Strategy 买入 603007.SH @ 5.85, 目标持仓: 5只 +[2026-02-25 00:39:30] [INFO] [logger.py:165] [MainThread] [订单执行成功] strategy=ST_Strategy, code=603007.SH, action=BUY, vol=100, price=5.85, order_id=-1 +[2026-02-25 00:39:30] [DEBUG] [logger.py:185] [MainThread] [消息确认] stream=qmt:ST_Strategy:backtest, id=1771950790601-0, result=成功 +[2026-02-25 00:39:30] [DEBUG] [logger.py:89] [MainThread] [消息接收] stream=qmt:ST_Strategy:backtest, id=1771950790722-0, data={'strategy_name': 'ST_Strategy', 'stock_code': '002816.SZ', 'action': 'BUY', 'price': 22.65, 'total_slots': 5, 'timestamp': '2026-01-05 09:31:00', 'is_backtest': True} +[2026-02-25 00:39:30] [DEBUG] [logger.py:112] [MainThread] [消息解析] strategy=ST_Strategy, code=002816.SZ, action=BUY, price=22.65, extra={'total_slots': 5, 'timestamp': '2026-01-05 09:31:00', 'is_backtest': True} +[2026-02-25 00:39:30] [DEBUG] [logger.py:133] [MainThread] [业务校验] type=field_check, strategy=ST_Strategy, result=通过, details={'fields': ['strategy_name', 'stock_code', 'action', 'price', 'total_slots', 'timestamp', 'is_backtest']} +[2026-02-25 00:39:30] [DEBUG] [logger.py:170] [MainThread] [订单执行请求] strategy=ST_Strategy, code=002816.SZ, action=BUY, vol=100, price=22.65 +[2026-02-25 00:39:30] [INFO] [logger.py:262] [MainThread] [模拟交易] ST_Strategy 买入 002816.SZ @ 22.65, 目标持仓: 5只 +[2026-02-25 00:39:30] [INFO] [logger.py:165] [MainThread] [订单执行成功] strategy=ST_Strategy, code=002816.SZ, action=BUY, vol=100, price=22.65, order_id=-1 +[2026-02-25 00:39:30] [DEBUG] [logger.py:185] [MainThread] [消息确认] stream=qmt:ST_Strategy:backtest, id=1771950790722-0, result=成功 +[2026-02-25 00:39:30] [DEBUG] [logger.py:89] [MainThread] [消息接收] stream=qmt:ST_Strategy:backtest, id=1771950790850-0, data={'strategy_name': 'ST_Strategy', 'stock_code': '605081.SH', 'action': 'BUY', 'price': 10.65, 'total_slots': 5, 'timestamp': '2026-01-05 09:31:00', 'is_backtest': True} +[2026-02-25 00:39:30] [DEBUG] [logger.py:112] [MainThread] [消息解析] strategy=ST_Strategy, code=605081.SH, action=BUY, price=10.65, extra={'total_slots': 5, 'timestamp': '2026-01-05 09:31:00', 'is_backtest': True} +[2026-02-25 00:39:30] [DEBUG] [logger.py:133] [MainThread] [业务校验] type=field_check, strategy=ST_Strategy, result=通过, details={'fields': ['strategy_name', 'stock_code', 'action', 'price', 'total_slots', 'timestamp', 'is_backtest']} +[2026-02-25 00:39:30] [DEBUG] [logger.py:170] [MainThread] [订单执行请求] strategy=ST_Strategy, code=605081.SH, action=BUY, vol=100, price=10.65 +[2026-02-25 00:39:30] [INFO] [logger.py:262] [MainThread] [模拟交易] ST_Strategy 买入 605081.SH @ 10.65, 目标持仓: 5只 +[2026-02-25 00:39:30] [INFO] [logger.py:165] [MainThread] [订单执行成功] strategy=ST_Strategy, code=605081.SH, action=BUY, vol=100, price=10.65, order_id=-1 +[2026-02-25 00:39:30] [DEBUG] [logger.py:185] [MainThread] [消息确认] stream=qmt:ST_Strategy:backtest, id=1771950790850-0, result=成功 +[2026-02-25 00:39:30] [DEBUG] [logger.py:89] [MainThread] [消息接收] stream=qmt:ST_Strategy:backtest, id=1771950790963-0, data={'strategy_name': 'ST_Strategy', 'stock_code': '002168.SZ', 'action': 'BUY', 'price': 4.29, 'total_slots': 5, 'timestamp': '2026-01-05 09:31:00', 'is_backtest': True} +[2026-02-25 00:39:30] [DEBUG] [logger.py:112] [MainThread] [消息解析] strategy=ST_Strategy, code=002168.SZ, action=BUY, price=4.29, extra={'total_slots': 5, 'timestamp': '2026-01-05 09:31:00', 'is_backtest': True} +[2026-02-25 00:39:30] [DEBUG] [logger.py:133] [MainThread] [业务校验] type=field_check, strategy=ST_Strategy, result=通过, details={'fields': ['strategy_name', 'stock_code', 'action', 'price', 'total_slots', 'timestamp', 'is_backtest']} +[2026-02-25 00:39:30] [DEBUG] [logger.py:170] [MainThread] [订单执行请求] strategy=ST_Strategy, code=002168.SZ, action=BUY, vol=100, price=4.29 +[2026-02-25 00:39:30] [INFO] [logger.py:262] [MainThread] [模拟交易] ST_Strategy 买入 002168.SZ @ 4.29, 目标持仓: 5只 +[2026-02-25 00:39:30] [INFO] [logger.py:165] [MainThread] [订单执行成功] strategy=ST_Strategy, code=002168.SZ, action=BUY, vol=100, price=4.29, order_id=-1 +[2026-02-25 00:39:30] [DEBUG] [logger.py:185] [MainThread] [消息确认] stream=qmt:ST_Strategy:backtest, id=1771950790963-0, result=成功 +[2026-02-25 00:39:30] [DEBUG] [logger.py:89] [MainThread] [消息接收] stream=qmt:ST_Strategy:backtest, id=1771950791074-0, data={'strategy_name': 'ST_Strategy', 'stock_code': '002485.SZ', 'action': 'BUY', 'price': 4.2, 'total_slots': 5, 'timestamp': '2026-01-05 09:31:00', 'is_backtest': True} +[2026-02-25 00:39:30] [DEBUG] [logger.py:112] [MainThread] [消息解析] strategy=ST_Strategy, code=002485.SZ, action=BUY, price=4.2, extra={'total_slots': 5, 'timestamp': '2026-01-05 09:31:00', 'is_backtest': True} +[2026-02-25 00:39:30] [DEBUG] [logger.py:133] [MainThread] [业务校验] type=field_check, strategy=ST_Strategy, result=通过, details={'fields': ['strategy_name', 'stock_code', 'action', 'price', 'total_slots', 'timestamp', 'is_backtest']} +[2026-02-25 00:39:30] [DEBUG] [logger.py:170] [MainThread] [订单执行请求] strategy=ST_Strategy, code=002485.SZ, action=BUY, vol=100, price=4.2 +[2026-02-25 00:39:30] [INFO] [logger.py:262] [MainThread] [模拟交易] ST_Strategy 买入 002485.SZ @ 4.2, 目标持仓: 5只 +[2026-02-25 00:39:30] [INFO] [logger.py:165] [MainThread] [订单执行成功] strategy=ST_Strategy, code=002485.SZ, action=BUY, vol=100, price=4.2, order_id=-1 +[2026-02-25 00:39:30] [DEBUG] [logger.py:185] [MainThread] [消息确认] stream=qmt:ST_Strategy:backtest, id=1771950791074-0, result=成功 +[2026-02-25 00:39:30] [DEBUG] [logger.py:89] [MainThread] [消息接收] stream=qmt:ST_Strategy:backtest, id=1771950791607-0, data={'strategy_name': 'ST_Strategy', 'stock_code': '002816.SZ', 'action': 'SELL', 'price': 22.99, 'total_slots': 0, 'timestamp': '2026-01-06 13:00:00', 'is_backtest': True} +[2026-02-25 00:39:30] [DEBUG] [logger.py:112] [MainThread] [消息解析] strategy=ST_Strategy, code=002816.SZ, action=SELL, price=22.99, extra={'total_slots': 0, 'timestamp': '2026-01-06 13:00:00', 'is_backtest': True} +[2026-02-25 00:39:30] [DEBUG] [logger.py:133] [MainThread] [业务校验] type=field_check, strategy=ST_Strategy, result=通过, details={'fields': ['strategy_name', 'stock_code', 'action', 'price', 'total_slots', 'timestamp', 'is_backtest']} +[2026-02-25 00:39:30] [DEBUG] [logger.py:170] [MainThread] [订单执行请求] strategy=ST_Strategy, code=002816.SZ, action=SELL, vol=100, price=22.99 +[2026-02-25 00:39:30] [INFO] [logger.py:262] [MainThread] [模拟交易] ST_Strategy 卖出 002816.SZ @ 22.99, 清仓释放槽位 +[2026-02-25 00:39:30] [INFO] [logger.py:165] [MainThread] [订单执行成功] strategy=ST_Strategy, code=002816.SZ, action=SELL, vol=100, price=22.99, order_id=-1 +[2026-02-25 00:39:30] [DEBUG] [logger.py:185] [MainThread] [消息确认] stream=qmt:ST_Strategy:backtest, id=1771950791607-0, result=成功 +[2026-02-25 00:39:30] [DEBUG] [logger.py:89] [MainThread] [消息接收] stream=qmt:ST_Strategy:backtest, id=1771950791734-0, data={'strategy_name': 'ST_Strategy', 'stock_code': '002168.SZ', 'action': 'SELL', 'price': 4.1, 'total_slots': 0, 'timestamp': '2026-01-06 13:00:00', 'is_backtest': True} +[2026-02-25 00:39:30] [DEBUG] [logger.py:112] [MainThread] [消息解析] strategy=ST_Strategy, code=002168.SZ, action=SELL, price=4.1, extra={'total_slots': 0, 'timestamp': '2026-01-06 13:00:00', 'is_backtest': True} +[2026-02-25 00:39:30] [DEBUG] [logger.py:133] [MainThread] [业务校验] type=field_check, strategy=ST_Strategy, result=通过, details={'fields': ['strategy_name', 'stock_code', 'action', 'price', 'total_slots', 'timestamp', 'is_backtest']} +[2026-02-25 00:39:30] [DEBUG] [logger.py:170] [MainThread] [订单执行请求] strategy=ST_Strategy, code=002168.SZ, action=SELL, vol=100, price=4.1 +[2026-02-25 00:39:30] [INFO] [logger.py:262] [MainThread] [模拟交易] ST_Strategy 卖出 002168.SZ @ 4.1, 清仓释放槽位 +[2026-02-25 00:39:30] [INFO] [logger.py:165] [MainThread] [订单执行成功] strategy=ST_Strategy, code=002168.SZ, action=SELL, vol=100, price=4.1, order_id=-1 +[2026-02-25 00:39:30] [DEBUG] [logger.py:185] [MainThread] [消息确认] stream=qmt:ST_Strategy:backtest, id=1771950791734-0, result=成功 +[2026-02-25 00:39:30] [DEBUG] [logger.py:89] [MainThread] [消息接收] stream=qmt:ST_Strategy:backtest, id=1771950791855-0, data={'strategy_name': 'ST_Strategy', 'stock_code': '002485.SZ', 'action': 'SELL', 'price': 4.36, 'total_slots': 0, 'timestamp': '2026-01-06 13:00:00', 'is_backtest': True} +[2026-02-25 00:39:30] [DEBUG] [logger.py:112] [MainThread] [消息解析] strategy=ST_Strategy, code=002485.SZ, action=SELL, price=4.36, extra={'total_slots': 0, 'timestamp': '2026-01-06 13:00:00', 'is_backtest': True} +[2026-02-25 00:39:30] [DEBUG] [logger.py:133] [MainThread] [业务校验] type=field_check, strategy=ST_Strategy, result=通过, details={'fields': ['strategy_name', 'stock_code', 'action', 'price', 'total_slots', 'timestamp', 'is_backtest']} +[2026-02-25 00:39:30] [DEBUG] [logger.py:170] [MainThread] [订单执行请求] strategy=ST_Strategy, code=002485.SZ, action=SELL, vol=100, price=4.36 +[2026-02-25 00:39:30] [INFO] [logger.py:262] [MainThread] [模拟交易] ST_Strategy 卖出 002485.SZ @ 4.36, 清仓释放槽位 +[2026-02-25 00:39:30] [INFO] [logger.py:165] [MainThread] [订单执行成功] strategy=ST_Strategy, code=002485.SZ, action=SELL, vol=100, price=4.36, order_id=-1 +[2026-02-25 00:39:30] [DEBUG] [logger.py:185] [MainThread] [消息确认] stream=qmt:ST_Strategy:backtest, id=1771950791855-0, result=成功 +[2026-02-25 00:39:30] [DEBUG] [logger.py:89] [MainThread] [消息接收] stream=qmt:ST_Strategy:backtest, id=1771950791972-0, data={'strategy_name': 'ST_Strategy', 'stock_code': '603007.SH', 'action': 'SELL', 'price': 5.9, 'total_slots': 0, 'timestamp': '2026-01-06 13:00:00', 'is_backtest': True} +[2026-02-25 00:39:30] [DEBUG] [logger.py:112] [MainThread] [消息解析] strategy=ST_Strategy, code=603007.SH, action=SELL, price=5.9, extra={'total_slots': 0, 'timestamp': '2026-01-06 13:00:00', 'is_backtest': True} +[2026-02-25 00:39:30] [DEBUG] [logger.py:133] [MainThread] [业务校验] type=field_check, strategy=ST_Strategy, result=通过, details={'fields': ['strategy_name', 'stock_code', 'action', 'price', 'total_slots', 'timestamp', 'is_backtest']} +[2026-02-25 00:39:30] [DEBUG] [logger.py:170] [MainThread] [订单执行请求] strategy=ST_Strategy, code=603007.SH, action=SELL, vol=100, price=5.9 +[2026-02-25 00:39:30] [INFO] [logger.py:262] [MainThread] [模拟交易] ST_Strategy 卖出 603007.SH @ 5.9, 清仓释放槽位 +[2026-02-25 00:39:30] [INFO] [logger.py:165] [MainThread] [订单执行成功] strategy=ST_Strategy, code=603007.SH, action=SELL, vol=100, price=5.9, order_id=-1 +[2026-02-25 00:39:30] [DEBUG] [logger.py:185] [MainThread] [消息确认] stream=qmt:ST_Strategy:backtest, id=1771950791972-0, result=成功 +[2026-02-25 00:39:30] [DEBUG] [logger.py:89] [MainThread] [消息接收] stream=qmt:ST_Strategy:backtest, id=1771950792727-0, data={'strategy_name': 'ST_Strategy', 'stock_code': '300561.SZ', 'action': 'BUY', 'price': 18.71, 'total_slots': 5, 'timestamp': '2026-01-07 09:31:00', 'is_backtest': True} +[2026-02-25 00:39:30] [DEBUG] [logger.py:112] [MainThread] [消息解析] strategy=ST_Strategy, code=300561.SZ, action=BUY, price=18.71, extra={'total_slots': 5, 'timestamp': '2026-01-07 09:31:00', 'is_backtest': True} +[2026-02-25 00:39:30] [DEBUG] [logger.py:133] [MainThread] [业务校验] type=field_check, strategy=ST_Strategy, result=通过, details={'fields': ['strategy_name', 'stock_code', 'action', 'price', 'total_slots', 'timestamp', 'is_backtest']} +[2026-02-25 00:39:30] [DEBUG] [logger.py:170] [MainThread] [订单执行请求] strategy=ST_Strategy, code=300561.SZ, action=BUY, vol=100, price=18.71 +[2026-02-25 00:39:31] [INFO] [logger.py:262] [MainThread] [模拟交易] ST_Strategy 买入 300561.SZ @ 18.71, 目标持仓: 5只 +[2026-02-25 00:39:31] [INFO] [logger.py:165] [MainThread] [订单执行成功] strategy=ST_Strategy, code=300561.SZ, action=BUY, vol=100, price=18.71, order_id=-1 +[2026-02-25 00:39:31] [DEBUG] [logger.py:185] [MainThread] [消息确认] stream=qmt:ST_Strategy:backtest, id=1771950792727-0, result=成功 +[2026-02-25 00:39:31] [INFO] [logger.py:262] [MainThread] [BacktestConsumer] 策略 ST_Strategy 处理 10 条消息 +[2026-02-25 00:39:31] [INFO] [logger.py:262] [MainThread] [BacktestConsumer] 单次运行完成,共处理 10 条消息 +[2026-02-25 00:39:31] [INFO] [logger.py:262] [MainThread] ================================================== +[2026-02-25 00:39:31] [INFO] [logger.py:262] [MainThread] [统计信息] +[2026-02-25 00:39:31] [INFO] [logger.py:262] [MainThread] 运行时间: 1.1 秒 +[2026-02-25 00:39:31] [INFO] [logger.py:262] [MainThread] 接收消息: 10 +[2026-02-25 00:39:31] [INFO] [logger.py:262] [MainThread] 处理成功: 10 +[2026-02-25 00:39:31] [INFO] [logger.py:262] [MainThread] 处理失败: 0 +[2026-02-25 00:39:31] [INFO] [logger.py:262] [MainThread] ================================================== +[2026-02-25 00:42:12] [DEBUG] [logger.py:77] [MainThread] [QMTLogger] 日志记录器初始化完成: BacktestConsumer +[2026-02-25 00:42:12] [INFO] [logger.py:262] [MainThread] [BacktestConsumer] 初始化完成 +[2026-02-25 00:42:12] [INFO] [logger.py:262] [MainThread] [BacktestConsumer] 消费者ID: backtest-consumer-1 +[2026-02-25 00:42:12] [INFO] [logger.py:262] [MainThread] [BacktestConsumer] 策略列表: 所有策略 +[2026-02-25 00:42:12] [INFO] [logger.py:262] [MainThread] [BacktestConsumer] 单次运行,策略: ['Multi_Strategy'] +[2026-02-25 00:42:12] [DEBUG] [logger.py:89] [MainThread] [消息接收] stream=qmt:Multi_Strategy:backtest, id=1771951291117-0, data={'strategy_name': 'Multi_Strategy', 'stock_code': '159949.SZ', 'action': 'BUY', 'price': 0.671, 'position_pct': 0.3, 'timestamp': '2020-01-03 10:00:00', 'is_backtest': True} +[2026-02-25 00:42:12] [DEBUG] [logger.py:112] [MainThread] [消息解析] strategy=Multi_Strategy, code=159949.SZ, action=BUY, price=0.671, extra={'total_slots': None, 'timestamp': '2020-01-03 10:00:00', 'is_backtest': True} +[2026-02-25 00:42:12] [DEBUG] [logger.py:133] [MainThread] [业务校验] type=field_check, strategy=Multi_Strategy, result=通过, details={'fields': ['strategy_name', 'stock_code', 'action', 'price', 'position_pct', 'timestamp', 'is_backtest']} +[2026-02-25 00:42:12] [DEBUG] [logger.py:170] [MainThread] [订单执行请求] strategy=Multi_Strategy, code=159949.SZ, action=BUY, vol=100, price=0.671 +[2026-02-25 00:42:12] [INFO] [logger.py:262] [MainThread] [模拟交易] Multi_Strategy 买入 159949.SZ @ 0.671, 目标持仓: 0只 +[2026-02-25 00:42:12] [INFO] [logger.py:165] [MainThread] [订单执行成功] strategy=Multi_Strategy, code=159949.SZ, action=BUY, vol=100, price=0.671, order_id=-1 +[2026-02-25 00:42:12] [DEBUG] [logger.py:185] [MainThread] [消息确认] stream=qmt:Multi_Strategy:backtest, id=1771951291117-0, result=成功 +[2026-02-25 00:42:12] [DEBUG] [logger.py:89] [MainThread] [消息接收] stream=qmt:Multi_Strategy:backtest, id=1771951291794-0, data={'strategy_name': 'Multi_Strategy', 'stock_code': '159949.SZ', 'action': 'SELL', 'price': 0.699, 'position_pct': 0.0, 'timestamp': '2020-01-15 10:00:00', 'is_backtest': True} +[2026-02-25 00:42:12] [DEBUG] [logger.py:112] [MainThread] [消息解析] strategy=Multi_Strategy, code=159949.SZ, action=SELL, price=0.699, extra={'total_slots': None, 'timestamp': '2020-01-15 10:00:00', 'is_backtest': True} +[2026-02-25 00:42:12] [DEBUG] [logger.py:133] [MainThread] [业务校验] type=field_check, strategy=Multi_Strategy, result=通过, details={'fields': ['strategy_name', 'stock_code', 'action', 'price', 'position_pct', 'timestamp', 'is_backtest']} +[2026-02-25 00:42:12] [DEBUG] [logger.py:170] [MainThread] [订单执行请求] strategy=Multi_Strategy, code=159949.SZ, action=SELL, vol=100, price=0.699 +[2026-02-25 00:42:12] [INFO] [logger.py:262] [MainThread] [模拟交易] Multi_Strategy 卖出 159949.SZ @ 0.699, 清仓释放槽位 +[2026-02-25 00:42:12] [INFO] [logger.py:165] [MainThread] [订单执行成功] strategy=Multi_Strategy, code=159949.SZ, action=SELL, vol=100, price=0.699, order_id=-1 +[2026-02-25 00:42:12] [DEBUG] [logger.py:185] [MainThread] [消息确认] stream=qmt:Multi_Strategy:backtest, id=1771951291794-0, result=成功 +[2026-02-25 00:42:12] [DEBUG] [logger.py:89] [MainThread] [消息接收] stream=qmt:Multi_Strategy:backtest, id=1771951291931-0, data={'strategy_name': 'Multi_Strategy', 'stock_code': '513100.SH', 'action': 'BUY', 'price': 3.39, 'position_pct': 0.30791624979455123, 'timestamp': '2020-01-15 10:00:00', 'is_backtest': True} +[2026-02-25 00:42:12] [DEBUG] [logger.py:112] [MainThread] [消息解析] strategy=Multi_Strategy, code=513100.SH, action=BUY, price=3.39, extra={'total_slots': None, 'timestamp': '2020-01-15 10:00:00', 'is_backtest': True} +[2026-02-25 00:42:12] [DEBUG] [logger.py:133] [MainThread] [业务校验] type=field_check, strategy=Multi_Strategy, result=通过, details={'fields': ['strategy_name', 'stock_code', 'action', 'price', 'position_pct', 'timestamp', 'is_backtest']} +[2026-02-25 00:42:12] [DEBUG] [logger.py:170] [MainThread] [订单执行请求] strategy=Multi_Strategy, code=513100.SH, action=BUY, vol=100, price=3.39 +[2026-02-25 00:42:12] [INFO] [logger.py:262] [MainThread] [模拟交易] Multi_Strategy 买入 513100.SH @ 3.39, 目标持仓: 0只 +[2026-02-25 00:42:12] [INFO] [logger.py:165] [MainThread] [订单执行成功] strategy=Multi_Strategy, code=513100.SH, action=BUY, vol=100, price=3.39, order_id=-1 +[2026-02-25 00:42:12] [DEBUG] [logger.py:185] [MainThread] [消息确认] stream=qmt:Multi_Strategy:backtest, id=1771951291931-0, result=成功 +[2026-02-25 00:42:12] [DEBUG] [logger.py:89] [MainThread] [消息接收] stream=qmt:Multi_Strategy:backtest, id=1771951292370-0, data={'strategy_name': 'Multi_Strategy', 'stock_code': '513100.SH', 'action': 'SELL', 'price': 3.426, 'position_pct': 0.0, 'timestamp': '2020-01-23 10:00:00', 'is_backtest': True} +[2026-02-25 00:42:12] [DEBUG] [logger.py:112] [MainThread] [消息解析] strategy=Multi_Strategy, code=513100.SH, action=SELL, price=3.426, extra={'total_slots': None, 'timestamp': '2020-01-23 10:00:00', 'is_backtest': True} +[2026-02-25 00:42:12] [DEBUG] [logger.py:133] [MainThread] [业务校验] type=field_check, strategy=Multi_Strategy, result=通过, details={'fields': ['strategy_name', 'stock_code', 'action', 'price', 'position_pct', 'timestamp', 'is_backtest']} +[2026-02-25 00:42:12] [DEBUG] [logger.py:170] [MainThread] [订单执行请求] strategy=Multi_Strategy, code=513100.SH, action=SELL, vol=100, price=3.426 +[2026-02-25 00:42:13] [INFO] [logger.py:262] [MainThread] [模拟交易] Multi_Strategy 卖出 513100.SH @ 3.426, 清仓释放槽位 +[2026-02-25 00:42:13] [INFO] [logger.py:165] [MainThread] [订单执行成功] strategy=Multi_Strategy, code=513100.SH, action=SELL, vol=100, price=3.426, order_id=-1 +[2026-02-25 00:42:13] [DEBUG] [logger.py:185] [MainThread] [消息确认] stream=qmt:Multi_Strategy:backtest, id=1771951292370-0, result=成功 +[2026-02-25 00:42:13] [DEBUG] [logger.py:89] [MainThread] [消息接收] stream=qmt:Multi_Strategy:backtest, id=1771951292510-0, data={'strategy_name': 'Multi_Strategy', 'stock_code': '159949.SZ', 'action': 'BUY', 'price': 0.735, 'position_pct': 0.3095427886528769, 'timestamp': '2020-01-23 10:00:00', 'is_backtest': True} +[2026-02-25 00:42:13] [DEBUG] [logger.py:112] [MainThread] [消息解析] strategy=Multi_Strategy, code=159949.SZ, action=BUY, price=0.735, extra={'total_slots': None, 'timestamp': '2020-01-23 10:00:00', 'is_backtest': True} +[2026-02-25 00:42:13] [DEBUG] [logger.py:133] [MainThread] [业务校验] type=field_check, strategy=Multi_Strategy, result=通过, details={'fields': ['strategy_name', 'stock_code', 'action', 'price', 'position_pct', 'timestamp', 'is_backtest']} +[2026-02-25 00:42:13] [DEBUG] [logger.py:170] [MainThread] [订单执行请求] strategy=Multi_Strategy, code=159949.SZ, action=BUY, vol=100, price=0.735 +[2026-02-25 00:42:13] [INFO] [logger.py:262] [MainThread] [模拟交易] Multi_Strategy 买入 159949.SZ @ 0.735, 目标持仓: 0只 +[2026-02-25 00:42:13] [INFO] [logger.py:165] [MainThread] [订单执行成功] strategy=Multi_Strategy, code=159949.SZ, action=BUY, vol=100, price=0.735, order_id=-1 +[2026-02-25 00:42:13] [DEBUG] [logger.py:185] [MainThread] [消息确认] stream=qmt:Multi_Strategy:backtest, id=1771951292510-0, result=成功 +[2026-02-25 00:42:13] [DEBUG] [logger.py:89] [MainThread] [消息接收] stream=qmt:Multi_Strategy:backtest, id=1771951300387-0, data={'strategy_name': 'Multi_Strategy', 'stock_code': '600449.SH', 'action': 'BUY', 'price': 9.23, 'position_pct': 0.1023527508688942, 'timestamp': '2020-02-03 09:35:00', 'is_backtest': True} +[2026-02-25 00:42:13] [DEBUG] [logger.py:112] [MainThread] [消息解析] strategy=Multi_Strategy, code=600449.SH, action=BUY, price=9.23, extra={'total_slots': None, 'timestamp': '2020-02-03 09:35:00', 'is_backtest': True} +[2026-02-25 00:42:13] [DEBUG] [logger.py:133] [MainThread] [业务校验] type=field_check, strategy=Multi_Strategy, result=通过, details={'fields': ['strategy_name', 'stock_code', 'action', 'price', 'position_pct', 'timestamp', 'is_backtest']} +[2026-02-25 00:42:13] [DEBUG] [logger.py:170] [MainThread] [订单执行请求] strategy=Multi_Strategy, code=600449.SH, action=BUY, vol=100, price=9.23 +[2026-02-25 00:42:13] [INFO] [logger.py:262] [MainThread] [模拟交易] Multi_Strategy 买入 600449.SH @ 9.23, 目标持仓: 0只 +[2026-02-25 00:42:13] [INFO] [logger.py:165] [MainThread] [订单执行成功] strategy=Multi_Strategy, code=600449.SH, action=BUY, vol=100, price=9.23, order_id=-1 +[2026-02-25 00:42:13] [DEBUG] [logger.py:185] [MainThread] [消息确认] stream=qmt:Multi_Strategy:backtest, id=1771951300387-0, result=成功 +[2026-02-25 00:42:13] [DEBUG] [logger.py:89] [MainThread] [消息接收] stream=qmt:Multi_Strategy:backtest, id=1771951300521-0, data={'strategy_name': 'Multi_Strategy', 'stock_code': '002921.SZ', 'action': 'BUY', 'price': 15.92, 'position_pct': 0.08188470708731618, 'timestamp': '2020-02-03 09:35:00', 'is_backtest': True} +[2026-02-25 00:42:13] [DEBUG] [logger.py:112] [MainThread] [消息解析] strategy=Multi_Strategy, code=002921.SZ, action=BUY, price=15.92, extra={'total_slots': None, 'timestamp': '2020-02-03 09:35:00', 'is_backtest': True} +[2026-02-25 00:42:13] [DEBUG] [logger.py:133] [MainThread] [业务校验] type=field_check, strategy=Multi_Strategy, result=通过, details={'fields': ['strategy_name', 'stock_code', 'action', 'price', 'position_pct', 'timestamp', 'is_backtest']} +[2026-02-25 00:42:13] [DEBUG] [logger.py:170] [MainThread] [订单执行请求] strategy=Multi_Strategy, code=002921.SZ, action=BUY, vol=100, price=15.92 +[2026-02-25 00:42:13] [INFO] [logger.py:262] [MainThread] [模拟交易] Multi_Strategy 买入 002921.SZ @ 15.92, 目标持仓: 0只 +[2026-02-25 00:42:13] [INFO] [logger.py:165] [MainThread] [订单执行成功] strategy=Multi_Strategy, code=002921.SZ, action=BUY, vol=100, price=15.92, order_id=-1 +[2026-02-25 00:42:13] [DEBUG] [logger.py:185] [MainThread] [消息确认] stream=qmt:Multi_Strategy:backtest, id=1771951300521-0, result=成功 +[2026-02-25 00:42:13] [DEBUG] [logger.py:89] [MainThread] [消息接收] stream=qmt:Multi_Strategy:backtest, id=1771951300665-0, data={'strategy_name': 'Multi_Strategy', 'stock_code': '002857.SZ', 'action': 'BUY', 'price': 10.85, 'position_pct': 0.08188670861015712, 'timestamp': '2020-02-03 09:35:00', 'is_backtest': True} +[2026-02-25 00:42:13] [DEBUG] [logger.py:112] [MainThread] [消息解析] strategy=Multi_Strategy, code=002857.SZ, action=BUY, price=10.85, extra={'total_slots': None, 'timestamp': '2020-02-03 09:35:00', 'is_backtest': True} +[2026-02-25 00:42:13] [DEBUG] [logger.py:133] [MainThread] [业务校验] type=field_check, strategy=Multi_Strategy, result=通过, details={'fields': ['strategy_name', 'stock_code', 'action', 'price', 'position_pct', 'timestamp', 'is_backtest']} +[2026-02-25 00:42:13] [DEBUG] [logger.py:170] [MainThread] [订单执行请求] strategy=Multi_Strategy, code=002857.SZ, action=BUY, vol=100, price=10.85 +[2026-02-25 00:42:13] [INFO] [logger.py:262] [MainThread] [模拟交易] Multi_Strategy 买入 002857.SZ @ 10.85, 目标持仓: 0只 +[2026-02-25 00:42:13] [INFO] [logger.py:165] [MainThread] [订单执行成功] strategy=Multi_Strategy, code=002857.SZ, action=BUY, vol=100, price=10.85, order_id=-1 +[2026-02-25 00:42:13] [DEBUG] [logger.py:185] [MainThread] [消息确认] stream=qmt:Multi_Strategy:backtest, id=1771951300665-0, result=成功 +[2026-02-25 00:42:13] [DEBUG] [logger.py:89] [MainThread] [消息接收] stream=qmt:Multi_Strategy:backtest, id=1771951300804-0, data={'strategy_name': 'Multi_Strategy', 'stock_code': '002136.SZ', 'action': 'BUY', 'price': 6.5, 'position_pct': 0.08188870029794056, 'timestamp': '2020-02-03 09:35:00', 'is_backtest': True} +[2026-02-25 00:42:13] [DEBUG] [logger.py:112] [MainThread] [消息解析] strategy=Multi_Strategy, code=002136.SZ, action=BUY, price=6.5, extra={'total_slots': None, 'timestamp': '2020-02-03 09:35:00', 'is_backtest': True} +[2026-02-25 00:42:13] [DEBUG] [logger.py:133] [MainThread] [业务校验] type=field_check, strategy=Multi_Strategy, result=通过, details={'fields': ['strategy_name', 'stock_code', 'action', 'price', 'position_pct', 'timestamp', 'is_backtest']} +[2026-02-25 00:42:13] [DEBUG] [logger.py:170] [MainThread] [订单执行请求] strategy=Multi_Strategy, code=002136.SZ, action=BUY, vol=100, price=6.5 +[2026-02-25 00:42:13] [INFO] [logger.py:262] [MainThread] [模拟交易] Multi_Strategy 买入 002136.SZ @ 6.5, 目标持仓: 0只 +[2026-02-25 00:42:13] [INFO] [logger.py:165] [MainThread] [订单执行成功] strategy=Multi_Strategy, code=002136.SZ, action=BUY, vol=100, price=6.5, order_id=-1 +[2026-02-25 00:42:13] [DEBUG] [logger.py:185] [MainThread] [消息确认] stream=qmt:Multi_Strategy:backtest, id=1771951300804-0, result=成功 +[2026-02-25 00:42:13] [DEBUG] [logger.py:89] [MainThread] [消息接收] stream=qmt:Multi_Strategy:backtest, id=1771951300947-0, data={'strategy_name': 'Multi_Strategy', 'stock_code': '002843.SZ', 'action': 'BUY', 'price': 7.07, 'position_pct': 0.08189071081774243, 'timestamp': '2020-02-03 09:35:00', 'is_backtest': True} +[2026-02-25 00:42:13] [DEBUG] [logger.py:112] [MainThread] [消息解析] strategy=Multi_Strategy, code=002843.SZ, action=BUY, price=7.07, extra={'total_slots': None, 'timestamp': '2020-02-03 09:35:00', 'is_backtest': True} +[2026-02-25 00:42:13] [DEBUG] [logger.py:133] [MainThread] [业务校验] type=field_check, strategy=Multi_Strategy, result=通过, details={'fields': ['strategy_name', 'stock_code', 'action', 'price', 'position_pct', 'timestamp', 'is_backtest']} +[2026-02-25 00:42:13] [DEBUG] [logger.py:170] [MainThread] [订单执行请求] strategy=Multi_Strategy, code=002843.SZ, action=BUY, vol=100, price=7.07 +[2026-02-25 00:42:13] [INFO] [logger.py:262] [MainThread] [模拟交易] Multi_Strategy 买入 002843.SZ @ 7.07, 目标持仓: 0只 +[2026-02-25 00:42:13] [INFO] [logger.py:165] [MainThread] [订单执行成功] strategy=Multi_Strategy, code=002843.SZ, action=BUY, vol=100, price=7.07, order_id=-1 +[2026-02-25 00:42:13] [DEBUG] [logger.py:185] [MainThread] [消息确认] stream=qmt:Multi_Strategy:backtest, id=1771951300947-0, result=成功 +[2026-02-25 00:42:13] [INFO] [logger.py:262] [MainThread] [BacktestConsumer] 策略 Multi_Strategy 处理 10 条消息 +[2026-02-25 00:42:13] [INFO] [logger.py:262] [MainThread] [BacktestConsumer] 单次运行完成,共处理 10 条消息 +[2026-02-25 00:42:13] [INFO] [logger.py:262] [MainThread] ================================================== +[2026-02-25 00:42:13] [INFO] [logger.py:262] [MainThread] [统计信息] +[2026-02-25 00:42:13] [INFO] [logger.py:262] [MainThread] 运行时间: 1.2 秒 +[2026-02-25 00:42:13] [INFO] [logger.py:262] [MainThread] 接收消息: 10 +[2026-02-25 00:42:13] [INFO] [logger.py:262] [MainThread] 处理成功: 10 +[2026-02-25 00:42:13] [INFO] [logger.py:262] [MainThread] 处理失败: 0 +[2026-02-25 00:42:13] [INFO] [logger.py:262] [MainThread] ================================================== diff --git a/main/data/finance.ipynb b/main/data/finance.ipynb index 4d3bb4e..59adca0 100644 --- a/main/data/finance.ipynb +++ b/main/data/finance.ipynb @@ -11606,7 +11606,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "id": "83403f50", "metadata": {}, "outputs": [ @@ -12851,7 +12851,4481 @@ "成功获取 002771.SZ 的数据\n", "成功获取 002772.SZ 的数据\n", "成功获取 002773.SZ 的数据\n", - "成功获取 002774.SZ 的数据\n" + "成功获取 002774.SZ 的数据\n", + "成功获取 002775.SZ 的数据\n", + "成功获取 002777.SZ 的数据\n", + "成功获取 002778.SZ 的数据\n", + "成功获取 002779.SZ 的数据\n", + "成功获取 002780.SZ 的数据\n", + "成功获取 002782.SZ 的数据\n", + "成功获取 002783.SZ 的数据\n", + "成功获取 002785.SZ 的数据\n", + "成功获取 002786.SZ 的数据\n", + "成功获取 002787.SZ 的数据\n", + "成功获取 002788.SZ 的数据\n", + "成功获取 002789.SZ 的数据\n", + "成功获取 002790.SZ 的数据\n", + "成功获取 002791.SZ 的数据\n", + "成功获取 002792.SZ 的数据\n", + "成功获取 002793.SZ 的数据\n", + "成功获取 002795.SZ 的数据\n", + "成功获取 002796.SZ 的数据\n", + "成功获取 002797.SZ 的数据\n", + "成功获取 002798.SZ 的数据\n", + "成功获取 002799.SZ 的数据\n", + "成功获取 002800.SZ 的数据\n", + "成功获取 002801.SZ 的数据\n", + "成功获取 002802.SZ 的数据\n", + "成功获取 002803.SZ 的数据\n", + "成功获取 002805.SZ 的数据\n", + "成功获取 002806.SZ 的数据\n", + "成功获取 002807.SZ 的数据\n", + "成功获取 002808.SZ 的数据\n", + "成功获取 002809.SZ 的数据\n", + "成功获取 002810.SZ 的数据\n", + "成功获取 002811.SZ 的数据\n", + "成功获取 002812.SZ 的数据\n", + "成功获取 002813.SZ 的数据\n", + "成功获取 002815.SZ 的数据\n", + "成功获取 002816.SZ 的数据\n", + "成功获取 002817.SZ 的数据\n", + "成功获取 002818.SZ 的数据\n", + "成功获取 002819.SZ 的数据\n", + "成功获取 002820.SZ 的数据\n", + "成功获取 002821.SZ 的数据\n", + "成功获取 002822.SZ 的数据\n", + "成功获取 002823.SZ 的数据\n", + "成功获取 002824.SZ 的数据\n", + "成功获取 002825.SZ 的数据\n", + "成功获取 002826.SZ 的数据\n", + "成功获取 002827.SZ 的数据\n", + "成功获取 002828.SZ 的数据\n", + "成功获取 002829.SZ 的数据\n", + "成功获取 002830.SZ 的数据\n", + "成功获取 002831.SZ 的数据\n", + "成功获取 002832.SZ 的数据\n", + "成功获取 002833.SZ 的数据\n", + "成功获取 002835.SZ 的数据\n", + "成功获取 002836.SZ 的数据\n", + "成功获取 002837.SZ 的数据\n", + "成功获取 002838.SZ 的数据\n", + "成功获取 002839.SZ 的数据\n", + "成功获取 002840.SZ 的数据\n", + "成功获取 002841.SZ 的数据\n", + "成功获取 002842.SZ 的数据\n", + "成功获取 002843.SZ 的数据\n", + "成功获取 002845.SZ 的数据\n", + "成功获取 002846.SZ 的数据\n", + "成功获取 002847.SZ 的数据\n", + "成功获取 002848.SZ 的数据\n", + "成功获取 002849.SZ 的数据\n", + "成功获取 002850.SZ 的数据\n", + "成功获取 002851.SZ 的数据\n", + "成功获取 002852.SZ 的数据\n", + "成功获取 002853.SZ 的数据\n", + "成功获取 002855.SZ 的数据\n", + "成功获取 002856.SZ 的数据\n", + "成功获取 002857.SZ 的数据\n", + "成功获取 002858.SZ 的数据\n", + "成功获取 002859.SZ 的数据\n", + "成功获取 002860.SZ 的数据\n", + "成功获取 002861.SZ 的数据\n", + "成功获取 002862.SZ 的数据\n", + "成功获取 002863.SZ 的数据\n", + "成功获取 002864.SZ 的数据\n", + "成功获取 002865.SZ 的数据\n", + "成功获取 002866.SZ 的数据\n", + "成功获取 002867.SZ 的数据\n", + "成功获取 002868.SZ 的数据\n", + "成功获取 002869.SZ 的数据\n", + "成功获取 002870.SZ 的数据\n", + "成功获取 002871.SZ 的数据\n", + "成功获取 002872.SZ 的数据\n", + "成功获取 002873.SZ 的数据\n", + "成功获取 002875.SZ 的数据\n", + "成功获取 002876.SZ 的数据\n", + "成功获取 002877.SZ 的数据\n", + "成功获取 002878.SZ 的数据\n", + "成功获取 002879.SZ 的数据\n", + "成功获取 002880.SZ 的数据\n", + "成功获取 002881.SZ 的数据\n", + "成功获取 002882.SZ 的数据\n", + "成功获取 002883.SZ 的数据\n", + "成功获取 002884.SZ 的数据\n", + "成功获取 002885.SZ 的数据\n", + "成功获取 002886.SZ 的数据\n", + "成功获取 002887.SZ 的数据\n", + "成功获取 002888.SZ 的数据\n", + "成功获取 002889.SZ 的数据\n", + "成功获取 002890.SZ 的数据\n", + "成功获取 002891.SZ 的数据\n", + "成功获取 002892.SZ 的数据\n", + "成功获取 002893.SZ 的数据\n", + "成功获取 002895.SZ 的数据\n", + "成功获取 002896.SZ 的数据\n", + "成功获取 002897.SZ 的数据\n", + "成功获取 002898.SZ 的数据\n", + "成功获取 002899.SZ 的数据\n", + "成功获取 002900.SZ 的数据\n", + "成功获取 002901.SZ 的数据\n", + "成功获取 002902.SZ 的数据\n", + "成功获取 002903.SZ 的数据\n", + "成功获取 002905.SZ 的数据\n", + "成功获取 002906.SZ 的数据\n", + "成功获取 002907.SZ 的数据\n", + "成功获取 002908.SZ 的数据\n", + "成功获取 002909.SZ 的数据\n", + "成功获取 002910.SZ 的数据\n", + "成功获取 002911.SZ 的数据\n", + "成功获取 002912.SZ 的数据\n", + "成功获取 002913.SZ 的数据\n", + "成功获取 002915.SZ 的数据\n", + "成功获取 002916.SZ 的数据\n", + "成功获取 002917.SZ 的数据\n", + "成功获取 002918.SZ 的数据\n", + "成功获取 002919.SZ 的数据\n", + "成功获取 002920.SZ 的数据\n", + "成功获取 002921.SZ 的数据\n", + "成功获取 002922.SZ 的数据\n", + "成功获取 002923.SZ 的数据\n", + "成功获取 002925.SZ 的数据\n", + "成功获取 002926.SZ 的数据\n", + "成功获取 002927.SZ 的数据\n", + "成功获取 002928.SZ 的数据\n", + "成功获取 002929.SZ 的数据\n", + "成功获取 002930.SZ 的数据\n", + "成功获取 002931.SZ 的数据\n", + "成功获取 002932.SZ 的数据\n", + "成功获取 002933.SZ 的数据\n", + "成功获取 002935.SZ 的数据\n", + "成功获取 002936.SZ 的数据\n", + "成功获取 002937.SZ 的数据\n", + "成功获取 002938.SZ 的数据\n", + "成功获取 002939.SZ 的数据\n", + "成功获取 002940.SZ 的数据\n", + "成功获取 002941.SZ 的数据\n", + "成功获取 002942.SZ 的数据\n", + "成功获取 002943.SZ 的数据\n", + "成功获取 002945.SZ 的数据\n", + "成功获取 002946.SZ 的数据\n", + "成功获取 002947.SZ 的数据\n", + "成功获取 002948.SZ 的数据\n", + "成功获取 002949.SZ 的数据\n", + "成功获取 002950.SZ 的数据\n", + "成功获取 002951.SZ 的数据\n", + "成功获取 002952.SZ 的数据\n", + "成功获取 002953.SZ 的数据\n", + "成功获取 002955.SZ 的数据\n", + "成功获取 002956.SZ 的数据\n", + "成功获取 002957.SZ 的数据\n", + "成功获取 002958.SZ 的数据\n", + "成功获取 002959.SZ 的数据\n", + "成功获取 002960.SZ 的数据\n", + "成功获取 002961.SZ 的数据\n", + "成功获取 002962.SZ 的数据\n", + "成功获取 002963.SZ 的数据\n", + "成功获取 002965.SZ 的数据\n", + "成功获取 002966.SZ 的数据\n", + "成功获取 002967.SZ 的数据\n", + "成功获取 002968.SZ 的数据\n", + "成功获取 002969.SZ 的数据\n", + "成功获取 002970.SZ 的数据\n", + "成功获取 002971.SZ 的数据\n", + "成功获取 002972.SZ 的数据\n", + "成功获取 002973.SZ 的数据\n", + "成功获取 002975.SZ 的数据\n", + "成功获取 002976.SZ 的数据\n", + "成功获取 002977.SZ 的数据\n", + "成功获取 002978.SZ 的数据\n", + "成功获取 002979.SZ 的数据\n", + "成功获取 002980.SZ 的数据\n", + "成功获取 002981.SZ 的数据\n", + "成功获取 002982.SZ 的数据\n", + "成功获取 002983.SZ 的数据\n", + "成功获取 002984.SZ 的数据\n", + "成功获取 002985.SZ 的数据\n", + "成功获取 002986.SZ 的数据\n", + "成功获取 002987.SZ 的数据\n", + "成功获取 002988.SZ 的数据\n", + "成功获取 002989.SZ 的数据\n", + "成功获取 002990.SZ 的数据\n", + "成功获取 002991.SZ 的数据\n", + "成功获取 002992.SZ 的数据\n", + "成功获取 002993.SZ 的数据\n", + "成功获取 002995.SZ 的数据\n", + "成功获取 002996.SZ 的数据\n", + "成功获取 002997.SZ 的数据\n", + "成功获取 002998.SZ 的数据\n", + "成功获取 002999.SZ 的数据\n", + "成功获取 003000.SZ 的数据\n", + "成功获取 003001.SZ 的数据\n", + "成功获取 003002.SZ 的数据\n", + "成功获取 003003.SZ 的数据\n", + "成功获取 003004.SZ 的数据\n", + "成功获取 003005.SZ 的数据\n", + "成功获取 003006.SZ 的数据\n", + "成功获取 003007.SZ 的数据\n", + "成功获取 003008.SZ 的数据\n", + "成功获取 003009.SZ 的数据\n", + "成功获取 003010.SZ 的数据\n", + "成功获取 003011.SZ 的数据\n", + "成功获取 003012.SZ 的数据\n", + "成功获取 003013.SZ 的数据\n", + "成功获取 003015.SZ 的数据\n", + "成功获取 003016.SZ 的数据\n", + "成功获取 003017.SZ 的数据\n", + "成功获取 003018.SZ 的数据\n", + "成功获取 003019.SZ 的数据\n", + "成功获取 003020.SZ 的数据\n", + "成功获取 003021.SZ 的数据\n", + "成功获取 003022.SZ 的数据\n", + "成功获取 003023.SZ 的数据\n", + "成功获取 003025.SZ 的数据\n", + "成功获取 003026.SZ 的数据\n", + "成功获取 003027.SZ 的数据\n", + "成功获取 003028.SZ 的数据\n", + "成功获取 003029.SZ 的数据\n", + "成功获取 003030.SZ 的数据\n", + "成功获取 003031.SZ 的数据\n", + "成功获取 003032.SZ 的数据\n", + "成功获取 003033.SZ 的数据\n", + "成功获取 003035.SZ 的数据\n", + "成功获取 003036.SZ 的数据\n", + "成功获取 003037.SZ 的数据\n", + "成功获取 003038.SZ 的数据\n", + "成功获取 003039.SZ 的数据\n", + "成功获取 003040.SZ 的数据\n", + "成功获取 003041.SZ 的数据\n", + "成功获取 003042.SZ 的数据\n", + "成功获取 003043.SZ 的数据\n", + "成功获取 003816.SZ 的数据\n", + "成功获取 300001.SZ 的数据\n", + "成功获取 300002.SZ 的数据\n", + "成功获取 300003.SZ 的数据\n", + "成功获取 300004.SZ 的数据\n", + "成功获取 300005.SZ 的数据\n", + "成功获取 300006.SZ 的数据\n", + "成功获取 300007.SZ 的数据\n", + "成功获取 300008.SZ 的数据\n", + "成功获取 300009.SZ 的数据\n", + "成功获取 300010.SZ 的数据\n", + "成功获取 300011.SZ 的数据\n", + "成功获取 300012.SZ 的数据\n", + "成功获取 300013.SZ 的数据\n", + "成功获取 300014.SZ 的数据\n", + "成功获取 300015.SZ 的数据\n", + "成功获取 300016.SZ 的数据\n", + "已调用300次API,等待 4.63 秒以满足速率限制...\n", + "成功获取 300017.SZ 的数据\n", + "成功获取 300018.SZ 的数据\n", + "成功获取 300019.SZ 的数据\n", + "成功获取 300020.SZ 的数据\n", + "成功获取 300021.SZ 的数据\n", + "成功获取 300022.SZ 的数据\n", + "成功获取 300024.SZ 的数据\n", + "成功获取 300025.SZ 的数据\n", + "成功获取 300026.SZ 的数据\n", + "成功获取 300027.SZ 的数据\n", + "成功获取 300029.SZ 的数据\n", + "成功获取 300030.SZ 的数据\n", + "成功获取 300031.SZ 的数据\n", + "成功获取 300032.SZ 的数据\n", + "成功获取 300033.SZ 的数据\n", + "成功获取 300034.SZ 的数据\n", + "成功获取 300035.SZ 的数据\n", + "成功获取 300036.SZ 的数据\n", + "成功获取 300037.SZ 的数据\n", + "成功获取 300039.SZ 的数据\n", + "成功获取 300040.SZ 的数据\n", + "成功获取 300041.SZ 的数据\n", + "成功获取 300042.SZ 的数据\n", + "成功获取 300043.SZ 的数据\n", + "成功获取 300044.SZ 的数据\n", + "成功获取 300045.SZ 的数据\n", + "成功获取 300046.SZ 的数据\n", + "成功获取 300047.SZ 的数据\n", + "成功获取 300048.SZ 的数据\n", + "成功获取 300049.SZ 的数据\n", + "成功获取 300050.SZ 的数据\n", + "成功获取 300051.SZ 的数据\n", + "成功获取 300052.SZ 的数据\n", + "成功获取 300053.SZ 的数据\n", + "成功获取 300054.SZ 的数据\n", + "成功获取 300055.SZ 的数据\n", + "成功获取 300056.SZ 的数据\n", + "成功获取 300057.SZ 的数据\n", + "成功获取 300058.SZ 的数据\n", + "成功获取 300059.SZ 的数据\n", + "成功获取 300061.SZ 的数据\n", + "成功获取 300062.SZ 的数据\n", + "成功获取 300063.SZ 的数据\n", + "成功获取 300065.SZ 的数据\n", + "成功获取 300066.SZ 的数据\n", + "成功获取 300067.SZ 的数据\n", + "成功获取 300068.SZ 的数据\n", + "成功获取 300069.SZ 的数据\n", + "成功获取 300070.SZ 的数据\n", + "成功获取 300071.SZ 的数据\n", + "成功获取 300072.SZ 的数据\n", + "成功获取 300073.SZ 的数据\n", + "成功获取 300074.SZ 的数据\n", + "成功获取 300075.SZ 的数据\n", + "成功获取 300076.SZ 的数据\n", + "成功获取 300077.SZ 的数据\n", + "成功获取 300078.SZ 的数据\n", + "成功获取 300079.SZ 的数据\n", + "成功获取 300080.SZ 的数据\n", + "成功获取 300081.SZ 的数据\n", + "成功获取 300082.SZ 的数据\n", + "成功获取 300083.SZ 的数据\n", + "成功获取 300084.SZ 的数据\n", + "成功获取 300085.SZ 的数据\n", + "成功获取 300086.SZ 的数据\n", + "成功获取 300087.SZ 的数据\n", + "成功获取 300088.SZ 的数据\n", + "成功获取 300091.SZ 的数据\n", + "成功获取 300092.SZ 的数据\n", + "成功获取 300093.SZ 的数据\n", + "成功获取 300094.SZ 的数据\n", + "成功获取 300095.SZ 的数据\n", + "成功获取 300096.SZ 的数据\n", + "成功获取 300097.SZ 的数据\n", + "成功获取 300098.SZ 的数据\n", + "成功获取 300099.SZ 的数据\n", + "成功获取 300100.SZ 的数据\n", + "成功获取 300101.SZ 的数据\n", + "成功获取 300102.SZ 的数据\n", + "成功获取 300103.SZ 的数据\n", + "成功获取 300105.SZ 的数据\n", + "成功获取 300106.SZ 的数据\n", + "成功获取 300107.SZ 的数据\n", + "成功获取 300108.SZ 的数据\n", + "成功获取 300109.SZ 的数据\n", + "成功获取 300110.SZ 的数据\n", + "成功获取 300111.SZ 的数据\n", + "成功获取 300112.SZ 的数据\n", + "成功获取 300113.SZ 的数据\n", + "成功获取 300114.SZ 的数据\n", + "成功获取 300115.SZ 的数据\n", + "成功获取 300117.SZ 的数据\n", + "成功获取 300118.SZ 的数据\n", + "成功获取 300119.SZ 的数据\n", + "成功获取 300120.SZ 的数据\n", + "成功获取 300121.SZ 的数据\n", + "成功获取 300122.SZ 的数据\n", + "成功获取 300123.SZ 的数据\n", + "成功获取 300124.SZ 的数据\n", + "成功获取 300125.SZ 的数据\n", + "成功获取 300126.SZ 的数据\n", + "成功获取 300127.SZ 的数据\n", + "成功获取 300128.SZ 的数据\n", + "成功获取 300129.SZ 的数据\n", + "成功获取 300130.SZ 的数据\n", + "成功获取 300131.SZ 的数据\n", + "成功获取 300132.SZ 的数据\n", + "成功获取 300133.SZ 的数据\n", + "成功获取 300134.SZ 的数据\n", + "成功获取 300135.SZ 的数据\n", + "成功获取 300136.SZ 的数据\n", + "成功获取 300137.SZ 的数据\n", + "成功获取 300138.SZ 的数据\n", + "成功获取 300139.SZ 的数据\n", + "成功获取 300140.SZ 的数据\n", + "成功获取 300141.SZ 的数据\n", + "成功获取 300142.SZ 的数据\n", + "成功获取 300143.SZ 的数据\n", + "成功获取 300144.SZ 的数据\n", + "成功获取 300145.SZ 的数据\n", + "成功获取 300146.SZ 的数据\n", + "成功获取 300147.SZ 的数据\n", + "成功获取 300148.SZ 的数据\n", + "成功获取 300149.SZ 的数据\n", + "成功获取 300150.SZ 的数据\n", + "成功获取 300151.SZ 的数据\n", + "成功获取 300152.SZ 的数据\n", + "成功获取 300153.SZ 的数据\n", + "成功获取 300154.SZ 的数据\n", + "成功获取 300155.SZ 的数据\n", + "成功获取 300157.SZ 的数据\n", + "成功获取 300158.SZ 的数据\n", + "成功获取 300159.SZ 的数据\n", + "成功获取 300160.SZ 的数据\n", + "成功获取 300161.SZ 的数据\n", + "成功获取 300162.SZ 的数据\n", + "成功获取 300163.SZ 的数据\n", + "成功获取 300164.SZ 的数据\n", + "成功获取 300165.SZ 的数据\n", + "成功获取 300166.SZ 的数据\n", + "成功获取 300167.SZ 的数据\n", + "成功获取 300168.SZ 的数据\n", + "成功获取 300169.SZ 的数据\n", + "成功获取 300170.SZ 的数据\n", + "成功获取 300171.SZ 的数据\n", + "成功获取 300172.SZ 的数据\n", + "成功获取 300173.SZ 的数据\n", + "成功获取 300174.SZ 的数据\n", + "成功获取 300175.SZ 的数据\n", + "成功获取 300176.SZ 的数据\n", + "成功获取 300177.SZ 的数据\n", + "成功获取 300179.SZ 的数据\n", + "成功获取 300180.SZ 的数据\n", + "成功获取 300181.SZ 的数据\n", + "成功获取 300182.SZ 的数据\n", + "成功获取 300183.SZ 的数据\n", + "成功获取 300184.SZ 的数据\n", + "成功获取 300185.SZ 的数据\n", + "成功获取 300187.SZ 的数据\n", + "成功获取 300188.SZ 的数据\n", + "成功获取 300189.SZ 的数据\n", + "成功获取 300190.SZ 的数据\n", + "成功获取 300191.SZ 的数据\n", + "成功获取 300192.SZ 的数据\n", + "成功获取 300193.SZ 的数据\n", + "成功获取 300194.SZ 的数据\n", + "成功获取 300195.SZ 的数据\n", + "成功获取 300196.SZ 的数据\n", + "成功获取 300197.SZ 的数据\n", + "成功获取 300198.SZ 的数据\n", + "成功获取 300199.SZ 的数据\n", + "成功获取 300200.SZ 的数据\n", + "成功获取 300201.SZ 的数据\n", + "成功获取 300203.SZ 的数据\n", + "成功获取 300204.SZ 的数据\n", + "成功获取 300205.SZ 的数据\n", + "成功获取 300206.SZ 的数据\n", + "成功获取 300207.SZ 的数据\n", + "成功获取 300208.SZ 的数据\n", + "成功获取 300209.SZ 的数据\n", + "成功获取 300210.SZ 的数据\n", + "成功获取 300211.SZ 的数据\n", + "成功获取 300212.SZ 的数据\n", + "成功获取 300213.SZ 的数据\n", + "成功获取 300214.SZ 的数据\n", + "成功获取 300215.SZ 的数据\n", + "成功获取 300217.SZ 的数据\n", + "成功获取 300218.SZ 的数据\n", + "成功获取 300219.SZ 的数据\n", + "成功获取 300220.SZ 的数据\n", + "成功获取 300221.SZ 的数据\n", + "成功获取 300222.SZ 的数据\n", + "成功获取 300223.SZ 的数据\n", + "成功获取 300224.SZ 的数据\n", + "成功获取 300225.SZ 的数据\n", + "成功获取 300226.SZ 的数据\n", + "成功获取 300227.SZ 的数据\n", + "成功获取 300228.SZ 的数据\n", + "成功获取 300229.SZ 的数据\n", + "成功获取 300230.SZ 的数据\n", + "成功获取 300231.SZ 的数据\n", + "成功获取 300232.SZ 的数据\n", + "成功获取 300233.SZ 的数据\n", + "成功获取 300234.SZ 的数据\n", + "成功获取 300235.SZ 的数据\n", + "成功获取 300236.SZ 的数据\n", + "成功获取 300237.SZ 的数据\n", + "成功获取 300238.SZ 的数据\n", + "成功获取 300239.SZ 的数据\n", + "成功获取 300240.SZ 的数据\n", + "成功获取 300241.SZ 的数据\n", + "成功获取 300242.SZ 的数据\n", + "成功获取 300243.SZ 的数据\n", + "成功获取 300244.SZ 的数据\n", + "成功获取 300245.SZ 的数据\n", + "成功获取 300246.SZ 的数据\n", + "成功获取 300247.SZ 的数据\n", + "成功获取 300248.SZ 的数据\n", + "成功获取 300249.SZ 的数据\n", + "成功获取 300250.SZ 的数据\n", + "成功获取 300251.SZ 的数据\n", + "成功获取 300252.SZ 的数据\n", + "成功获取 300253.SZ 的数据\n", + "成功获取 300254.SZ 的数据\n", + "成功获取 300255.SZ 的数据\n", + "成功获取 300256.SZ 的数据\n", + "成功获取 300257.SZ 的数据\n", + "成功获取 300258.SZ 的数据\n", + "成功获取 300259.SZ 的数据\n", + "成功获取 300260.SZ 的数据\n", + "成功获取 300261.SZ 的数据\n", + "成功获取 300263.SZ 的数据\n", + "成功获取 300264.SZ 的数据\n", + "成功获取 300265.SZ 的数据\n", + "成功获取 300266.SZ 的数据\n", + "成功获取 300267.SZ 的数据\n", + "成功获取 300268.SZ 的数据\n", + "成功获取 300269.SZ 的数据\n", + "成功获取 300270.SZ 的数据\n", + "成功获取 300271.SZ 的数据\n", + "成功获取 300272.SZ 的数据\n", + "成功获取 300274.SZ 的数据\n", + "成功获取 300275.SZ 的数据\n", + "成功获取 300276.SZ 的数据\n", + "成功获取 300277.SZ 的数据\n", + "成功获取 300278.SZ 的数据\n", + "成功获取 300279.SZ 的数据\n", + "成功获取 300280.SZ 的数据\n", + "成功获取 300281.SZ 的数据\n", + "成功获取 300283.SZ 的数据\n", + "成功获取 300284.SZ 的数据\n", + "成功获取 300285.SZ 的数据\n", + "成功获取 300286.SZ 的数据\n", + "成功获取 300287.SZ 的数据\n", + "成功获取 300288.SZ 的数据\n", + "成功获取 300289.SZ 的数据\n", + "成功获取 300290.SZ 的数据\n", + "成功获取 300291.SZ 的数据\n", + "成功获取 300292.SZ 的数据\n", + "成功获取 300293.SZ 的数据\n", + "成功获取 300294.SZ 的数据\n", + "成功获取 300295.SZ 的数据\n", + "成功获取 300296.SZ 的数据\n", + "成功获取 300298.SZ 的数据\n", + "成功获取 300299.SZ 的数据\n", + "成功获取 300300.SZ 的数据\n", + "成功获取 300301.SZ 的数据\n", + "成功获取 300302.SZ 的数据\n", + "成功获取 300303.SZ 的数据\n", + "成功获取 300304.SZ 的数据\n", + "成功获取 300305.SZ 的数据\n", + "成功获取 300306.SZ 的数据\n", + "成功获取 300307.SZ 的数据\n", + "成功获取 300308.SZ 的数据\n", + "成功获取 300310.SZ 的数据\n", + "成功获取 300311.SZ 的数据\n", + "成功获取 300313.SZ 的数据\n", + "成功获取 300314.SZ 的数据\n", + "成功获取 300315.SZ 的数据\n", + "成功获取 300316.SZ 的数据\n", + "成功获取 300317.SZ 的数据\n", + "成功获取 300318.SZ 的数据\n", + "成功获取 300319.SZ 的数据\n", + "成功获取 300320.SZ 的数据\n", + "成功获取 300321.SZ 的数据\n", + "成功获取 300322.SZ 的数据\n", + "成功获取 300323.SZ 的数据\n", + "成功获取 300324.SZ 的数据\n", + "成功获取 300326.SZ 的数据\n", + "成功获取 300327.SZ 的数据\n", + "成功获取 300328.SZ 的数据\n", + "成功获取 300329.SZ 的数据\n", + "成功获取 300331.SZ 的数据\n", + "成功获取 300332.SZ 的数据\n", + "成功获取 300333.SZ 的数据\n", + "成功获取 300334.SZ 的数据\n", + "成功获取 300335.SZ 的数据\n", + "成功获取 300337.SZ 的数据\n", + "成功获取 300338.SZ 的数据\n", + "成功获取 300339.SZ 的数据\n", + "成功获取 300340.SZ 的数据\n", + "成功获取 300341.SZ 的数据\n", + "成功获取 300342.SZ 的数据\n", + "成功获取 300343.SZ 的数据\n", + "成功获取 300344.SZ 的数据\n", + "成功获取 300345.SZ 的数据\n", + "成功获取 300346.SZ 的数据\n", + "成功获取 300347.SZ 的数据\n", + "成功获取 300348.SZ 的数据\n", + "成功获取 300349.SZ 的数据\n", + "成功获取 300350.SZ 的数据\n", + "成功获取 300351.SZ 的数据\n", + "成功获取 300352.SZ 的数据\n", + "成功获取 300353.SZ 的数据\n", + "成功获取 300354.SZ 的数据\n", + "成功获取 300355.SZ 的数据\n", + "成功获取 300357.SZ 的数据\n", + "成功获取 300358.SZ 的数据\n", + "成功获取 300359.SZ 的数据\n", + "成功获取 300360.SZ 的数据\n", + "成功获取 300363.SZ 的数据\n", + "成功获取 300364.SZ 的数据\n", + "成功获取 300365.SZ 的数据\n", + "成功获取 300366.SZ 的数据\n", + "成功获取 300368.SZ 的数据\n", + "成功获取 300369.SZ 的数据\n", + "成功获取 300370.SZ 的数据\n", + "成功获取 300371.SZ 的数据\n", + "成功获取 300373.SZ 的数据\n", + "成功获取 300374.SZ 的数据\n", + "成功获取 300375.SZ 的数据\n", + "成功获取 300376.SZ 的数据\n", + "成功获取 300377.SZ 的数据\n", + "成功获取 300378.SZ 的数据\n", + "成功获取 300379.SZ 的数据\n", + "成功获取 300380.SZ 的数据\n", + "成功获取 300381.SZ 的数据\n", + "成功获取 300382.SZ 的数据\n", + "成功获取 300383.SZ 的数据\n", + "成功获取 300384.SZ 的数据\n", + "成功获取 300385.SZ 的数据\n", + "成功获取 300386.SZ 的数据\n", + "成功获取 300387.SZ 的数据\n", + "成功获取 300388.SZ 的数据\n", + "成功获取 300389.SZ 的数据\n", + "成功获取 300390.SZ 的数据\n", + "成功获取 300391.SZ 的数据\n", + "成功获取 300393.SZ 的数据\n", + "成功获取 300394.SZ 的数据\n", + "成功获取 300395.SZ 的数据\n", + "成功获取 300396.SZ 的数据\n", + "成功获取 300397.SZ 的数据\n", + "成功获取 300398.SZ 的数据\n", + "成功获取 300399.SZ 的数据\n", + "成功获取 300400.SZ 的数据\n", + "成功获取 300401.SZ 的数据\n", + "成功获取 300402.SZ 的数据\n", + "成功获取 300403.SZ 的数据\n", + "成功获取 300404.SZ 的数据\n", + "成功获取 300405.SZ 的数据\n", + "成功获取 300406.SZ 的数据\n", + "成功获取 300407.SZ 的数据\n", + "成功获取 300408.SZ 的数据\n", + "成功获取 300409.SZ 的数据\n", + "成功获取 300410.SZ 的数据\n", + "成功获取 300411.SZ 的数据\n", + "成功获取 300412.SZ 的数据\n", + "成功获取 300413.SZ 的数据\n", + "成功获取 300414.SZ 的数据\n", + "成功获取 300415.SZ 的数据\n", + "成功获取 300416.SZ 的数据\n", + "成功获取 300417.SZ 的数据\n", + "成功获取 300418.SZ 的数据\n", + "成功获取 300419.SZ 的数据\n", + "成功获取 300420.SZ 的数据\n", + "成功获取 300421.SZ 的数据\n", + "成功获取 300422.SZ 的数据\n", + "成功获取 300423.SZ 的数据\n", + "成功获取 300424.SZ 的数据\n", + "成功获取 300425.SZ 的数据\n", + "成功获取 300426.SZ 的数据\n", + "成功获取 300427.SZ 的数据\n", + "成功获取 300428.SZ 的数据\n", + "成功获取 300429.SZ 的数据\n", + "成功获取 300430.SZ 的数据\n", + "成功获取 300432.SZ 的数据\n", + "成功获取 300433.SZ 的数据\n", + "成功获取 300434.SZ 的数据\n", + "成功获取 300435.SZ 的数据\n", + "成功获取 300436.SZ 的数据\n", + "成功获取 300437.SZ 的数据\n", + "成功获取 300438.SZ 的数据\n", + "成功获取 300439.SZ 的数据\n", + "成功获取 300440.SZ 的数据\n", + "成功获取 300441.SZ 的数据\n", + "成功获取 300442.SZ 的数据\n", + "成功获取 300443.SZ 的数据\n", + "成功获取 300444.SZ 的数据\n", + "成功获取 300445.SZ 的数据\n", + "成功获取 300446.SZ 的数据\n", + "成功获取 300447.SZ 的数据\n", + "成功获取 300448.SZ 的数据\n", + "成功获取 300449.SZ 的数据\n", + "成功获取 300450.SZ 的数据\n", + "成功获取 300451.SZ 的数据\n", + "成功获取 300452.SZ 的数据\n", + "成功获取 300453.SZ 的数据\n", + "成功获取 300454.SZ 的数据\n", + "成功获取 300455.SZ 的数据\n", + "成功获取 300456.SZ 的数据\n", + "成功获取 300457.SZ 的数据\n", + "成功获取 300458.SZ 的数据\n", + "成功获取 300459.SZ 的数据\n", + "成功获取 300460.SZ 的数据\n", + "成功获取 300461.SZ 的数据\n", + "成功获取 300462.SZ 的数据\n", + "成功获取 300463.SZ 的数据\n", + "成功获取 300464.SZ 的数据\n", + "成功获取 300465.SZ 的数据\n", + "成功获取 300466.SZ 的数据\n", + "成功获取 300467.SZ 的数据\n", + "成功获取 300468.SZ 的数据\n", + "成功获取 300469.SZ 的数据\n", + "成功获取 300470.SZ 的数据\n", + "成功获取 300471.SZ 的数据\n", + "成功获取 300472.SZ 的数据\n", + "成功获取 300473.SZ 的数据\n", + "成功获取 300474.SZ 的数据\n", + "成功获取 300475.SZ 的数据\n", + "成功获取 300476.SZ 的数据\n", + "成功获取 300477.SZ 的数据\n", + "成功获取 300478.SZ 的数据\n", + "成功获取 300479.SZ 的数据\n", + "成功获取 300480.SZ 的数据\n", + "成功获取 300481.SZ 的数据\n", + "成功获取 300482.SZ 的数据\n", + "成功获取 300483.SZ 的数据\n", + "成功获取 300484.SZ 的数据\n", + "成功获取 300485.SZ 的数据\n", + "成功获取 300486.SZ 的数据\n", + "成功获取 300487.SZ 的数据\n", + "成功获取 300488.SZ 的数据\n", + "成功获取 300489.SZ 的数据\n", + "成功获取 300490.SZ 的数据\n", + "成功获取 300491.SZ 的数据\n", + "成功获取 300492.SZ 的数据\n", + "成功获取 300493.SZ 的数据\n", + "成功获取 300494.SZ 的数据\n", + "成功获取 300496.SZ 的数据\n", + "成功获取 300497.SZ 的数据\n", + "成功获取 300498.SZ 的数据\n", + "成功获取 300499.SZ 的数据\n", + "成功获取 300500.SZ 的数据\n", + "成功获取 300501.SZ 的数据\n", + "成功获取 300502.SZ 的数据\n", + "成功获取 300503.SZ 的数据\n", + "成功获取 300504.SZ 的数据\n", + "成功获取 300505.SZ 的数据\n", + "成功获取 300506.SZ 的数据\n", + "成功获取 300507.SZ 的数据\n", + "成功获取 300508.SZ 的数据\n", + "成功获取 300509.SZ 的数据\n", + "成功获取 300510.SZ 的数据\n", + "成功获取 300511.SZ 的数据\n", + "成功获取 300512.SZ 的数据\n", + "成功获取 300513.SZ 的数据\n", + "成功获取 300514.SZ 的数据\n", + "成功获取 300515.SZ 的数据\n", + "成功获取 300516.SZ 的数据\n", + "成功获取 300517.SZ 的数据\n", + "成功获取 300518.SZ 的数据\n", + "成功获取 300519.SZ 的数据\n", + "成功获取 300520.SZ 的数据\n", + "成功获取 300521.SZ 的数据\n", + "成功获取 300522.SZ 的数据\n", + "成功获取 300523.SZ 的数据\n", + "成功获取 300525.SZ 的数据\n", + "成功获取 300527.SZ 的数据\n", + "成功获取 300528.SZ 的数据\n", + "成功获取 300529.SZ 的数据\n", + "成功获取 300530.SZ 的数据\n", + "成功获取 300531.SZ 的数据\n", + "成功获取 300532.SZ 的数据\n", + "成功获取 300533.SZ 的数据\n", + "成功获取 300534.SZ 的数据\n", + "成功获取 300535.SZ 的数据\n", + "成功获取 300536.SZ 的数据\n", + "成功获取 300537.SZ 的数据\n", + "成功获取 300538.SZ 的数据\n", + "成功获取 300539.SZ 的数据\n", + "成功获取 300540.SZ 的数据\n", + "成功获取 300541.SZ 的数据\n", + "成功获取 300542.SZ 的数据\n", + "成功获取 300543.SZ 的数据\n", + "成功获取 300545.SZ 的数据\n", + "成功获取 300546.SZ 的数据\n", + "成功获取 300547.SZ 的数据\n", + "成功获取 300548.SZ 的数据\n", + "成功获取 300549.SZ 的数据\n", + "成功获取 300550.SZ 的数据\n", + "成功获取 300551.SZ 的数据\n", + "成功获取 300552.SZ 的数据\n", + "成功获取 300553.SZ 的数据\n", + "成功获取 300554.SZ 的数据\n", + "成功获取 300555.SZ 的数据\n", + "成功获取 300556.SZ 的数据\n", + "成功获取 300557.SZ 的数据\n", + "成功获取 300558.SZ 的数据\n", + "成功获取 300559.SZ 的数据\n", + "成功获取 300560.SZ 的数据\n", + "成功获取 300561.SZ 的数据\n", + "成功获取 300562.SZ 的数据\n", + "成功获取 300563.SZ 的数据\n", + "成功获取 300564.SZ 的数据\n", + "成功获取 300565.SZ 的数据\n", + "成功获取 300566.SZ 的数据\n", + "成功获取 300567.SZ 的数据\n", + "成功获取 300568.SZ 的数据\n", + "成功获取 300569.SZ 的数据\n", + "成功获取 300570.SZ 的数据\n", + "成功获取 300571.SZ 的数据\n", + "成功获取 300572.SZ 的数据\n", + "成功获取 300573.SZ 的数据\n", + "成功获取 300575.SZ 的数据\n", + "成功获取 300576.SZ 的数据\n", + "成功获取 300577.SZ 的数据\n", + "成功获取 300578.SZ 的数据\n", + "成功获取 300579.SZ 的数据\n", + "成功获取 300580.SZ 的数据\n", + "成功获取 300581.SZ 的数据\n", + "成功获取 300582.SZ 的数据\n", + "成功获取 300583.SZ 的数据\n", + "成功获取 300584.SZ 的数据\n", + "成功获取 300585.SZ 的数据\n", + "成功获取 300586.SZ 的数据\n", + "成功获取 300587.SZ 的数据\n", + "成功获取 300588.SZ 的数据\n", + "成功获取 300589.SZ 的数据\n", + "成功获取 300590.SZ 的数据\n", + "成功获取 300591.SZ 的数据\n", + "成功获取 300592.SZ 的数据\n", + "成功获取 300593.SZ 的数据\n", + "成功获取 300594.SZ 的数据\n", + "成功获取 300595.SZ 的数据\n", + "成功获取 300596.SZ 的数据\n", + "成功获取 300597.SZ 的数据\n", + "成功获取 300598.SZ 的数据\n", + "成功获取 300599.SZ 的数据\n", + "成功获取 300600.SZ 的数据\n", + "成功获取 300601.SZ 的数据\n", + "成功获取 300602.SZ 的数据\n", + "成功获取 300603.SZ 的数据\n", + "成功获取 300604.SZ 的数据\n", + "成功获取 300605.SZ 的数据\n", + "成功获取 300606.SZ 的数据\n", + "成功获取 300607.SZ 的数据\n", + "成功获取 300608.SZ 的数据\n", + "成功获取 300609.SZ 的数据\n", + "成功获取 300610.SZ 的数据\n", + "成功获取 300611.SZ 的数据\n", + "成功获取 300612.SZ 的数据\n", + "成功获取 300613.SZ 的数据\n", + "成功获取 300614.SZ 的数据\n", + "成功获取 300615.SZ 的数据\n", + "成功获取 300616.SZ 的数据\n", + "成功获取 300617.SZ 的数据\n", + "成功获取 300618.SZ 的数据\n", + "成功获取 300619.SZ 的数据\n", + "成功获取 300620.SZ 的数据\n", + "成功获取 300621.SZ 的数据\n", + "成功获取 300622.SZ 的数据\n", + "成功获取 300623.SZ 的数据\n", + "成功获取 300624.SZ 的数据\n", + "成功获取 300625.SZ 的数据\n", + "成功获取 300626.SZ 的数据\n", + "成功获取 300627.SZ 的数据\n", + "成功获取 300628.SZ 的数据\n", + "成功获取 300629.SZ 的数据\n", + "成功获取 300630.SZ 的数据\n", + "成功获取 300631.SZ 的数据\n", + "成功获取 300632.SZ 的数据\n", + "成功获取 300633.SZ 的数据\n", + "成功获取 300634.SZ 的数据\n", + "成功获取 300635.SZ 的数据\n", + "成功获取 300636.SZ 的数据\n", + "成功获取 300637.SZ 的数据\n", + "成功获取 300638.SZ 的数据\n", + "成功获取 300639.SZ 的数据\n", + "成功获取 300640.SZ 的数据\n", + "成功获取 300641.SZ 的数据\n", + "成功获取 300642.SZ 的数据\n", + "成功获取 300643.SZ 的数据\n", + "成功获取 300644.SZ 的数据\n", + "成功获取 300645.SZ 的数据\n", + "成功获取 300647.SZ 的数据\n", + "成功获取 300648.SZ 的数据\n", + "成功获取 300649.SZ 的数据\n", + "成功获取 300650.SZ 的数据\n", + "成功获取 300651.SZ 的数据\n", + "成功获取 300652.SZ 的数据\n", + "已调用300次API,等待 5.36 秒以满足速率限制...\n", + "成功获取 300653.SZ 的数据\n", + "成功获取 300654.SZ 的数据\n", + "成功获取 300655.SZ 的数据\n", + "成功获取 300656.SZ 的数据\n", + "成功获取 300657.SZ 的数据\n", + "成功获取 300658.SZ 的数据\n", + "成功获取 300659.SZ 的数据\n", + "成功获取 300660.SZ 的数据\n", + "成功获取 300661.SZ 的数据\n", + "成功获取 300662.SZ 的数据\n", + "成功获取 300663.SZ 的数据\n", + "成功获取 300664.SZ 的数据\n", + "成功获取 300665.SZ 的数据\n", + "成功获取 300666.SZ 的数据\n", + "成功获取 300667.SZ 的数据\n", + "成功获取 300668.SZ 的数据\n", + "成功获取 300669.SZ 的数据\n", + "成功获取 300670.SZ 的数据\n", + "成功获取 300671.SZ 的数据\n", + "成功获取 300672.SZ 的数据\n", + "成功获取 300673.SZ 的数据\n", + "成功获取 300674.SZ 的数据\n", + "成功获取 300675.SZ 的数据\n", + "成功获取 300676.SZ 的数据\n", + "成功获取 300677.SZ 的数据\n", + "成功获取 300678.SZ 的数据\n", + "成功获取 300679.SZ 的数据\n", + "成功获取 300680.SZ 的数据\n", + "成功获取 300681.SZ 的数据\n", + "成功获取 300682.SZ 的数据\n", + "成功获取 300683.SZ 的数据\n", + "成功获取 300684.SZ 的数据\n", + "成功获取 300685.SZ 的数据\n", + "成功获取 300686.SZ 的数据\n", + "成功获取 300687.SZ 的数据\n", + "成功获取 300688.SZ 的数据\n", + "成功获取 300689.SZ 的数据\n", + "成功获取 300690.SZ 的数据\n", + "成功获取 300691.SZ 的数据\n", + "成功获取 300692.SZ 的数据\n", + "成功获取 300693.SZ 的数据\n", + "成功获取 300694.SZ 的数据\n", + "成功获取 300695.SZ 的数据\n", + "成功获取 300696.SZ 的数据\n", + "成功获取 300697.SZ 的数据\n", + "成功获取 300698.SZ 的数据\n", + "成功获取 300699.SZ 的数据\n", + "成功获取 300700.SZ 的数据\n", + "成功获取 300701.SZ 的数据\n", + "成功获取 300702.SZ 的数据\n", + "成功获取 300703.SZ 的数据\n", + "成功获取 300705.SZ 的数据\n", + "成功获取 300706.SZ 的数据\n", + "成功获取 300707.SZ 的数据\n", + "成功获取 300708.SZ 的数据\n", + "成功获取 300709.SZ 的数据\n", + "成功获取 300710.SZ 的数据\n", + "成功获取 300711.SZ 的数据\n", + "成功获取 300712.SZ 的数据\n", + "成功获取 300713.SZ 的数据\n", + "成功获取 300715.SZ 的数据\n", + "成功获取 300716.SZ 的数据\n", + "成功获取 300717.SZ 的数据\n", + "成功获取 300718.SZ 的数据\n", + "成功获取 300719.SZ 的数据\n", + "成功获取 300720.SZ 的数据\n", + "成功获取 300721.SZ 的数据\n", + "成功获取 300722.SZ 的数据\n", + "成功获取 300723.SZ 的数据\n", + "成功获取 300724.SZ 的数据\n", + "成功获取 300725.SZ 的数据\n", + "成功获取 300726.SZ 的数据\n", + "成功获取 300727.SZ 的数据\n", + "成功获取 300729.SZ 的数据\n", + "成功获取 300730.SZ 的数据\n", + "成功获取 300731.SZ 的数据\n", + "成功获取 300732.SZ 的数据\n", + "成功获取 300733.SZ 的数据\n", + "成功获取 300735.SZ 的数据\n", + "成功获取 300736.SZ 的数据\n", + "成功获取 300737.SZ 的数据\n", + "成功获取 300738.SZ 的数据\n", + "成功获取 300739.SZ 的数据\n", + "成功获取 300740.SZ 的数据\n", + "成功获取 300741.SZ 的数据\n", + "成功获取 300743.SZ 的数据\n", + "成功获取 300745.SZ 的数据\n", + "成功获取 300746.SZ 的数据\n", + "成功获取 300747.SZ 的数据\n", + "成功获取 300748.SZ 的数据\n", + "成功获取 300749.SZ 的数据\n", + "成功获取 300750.SZ 的数据\n", + "成功获取 300751.SZ 的数据\n", + "成功获取 300752.SZ 的数据\n", + "成功获取 300753.SZ 的数据\n", + "成功获取 300755.SZ 的数据\n", + "成功获取 300756.SZ 的数据\n", + "成功获取 300757.SZ 的数据\n", + "成功获取 300758.SZ 的数据\n", + "成功获取 300759.SZ 的数据\n", + "成功获取 300760.SZ 的数据\n", + "成功获取 300761.SZ 的数据\n", + "成功获取 300762.SZ 的数据\n", + "成功获取 300763.SZ 的数据\n", + "成功获取 300765.SZ 的数据\n", + "成功获取 300766.SZ 的数据\n", + "成功获取 300767.SZ 的数据\n", + "成功获取 300768.SZ 的数据\n", + "成功获取 300769.SZ 的数据\n", + "成功获取 300770.SZ 的数据\n", + "成功获取 300771.SZ 的数据\n", + "成功获取 300772.SZ 的数据\n", + "成功获取 300773.SZ 的数据\n", + "成功获取 300774.SZ 的数据\n", + "成功获取 300775.SZ 的数据\n", + "成功获取 300776.SZ 的数据\n", + "成功获取 300777.SZ 的数据\n", + "成功获取 300778.SZ 的数据\n", + "成功获取 300779.SZ 的数据\n", + "成功获取 300780.SZ 的数据\n", + "成功获取 300781.SZ 的数据\n", + "成功获取 300782.SZ 的数据\n", + "成功获取 300783.SZ 的数据\n", + "成功获取 300784.SZ 的数据\n", + "成功获取 300785.SZ 的数据\n", + "成功获取 300786.SZ 的数据\n", + "成功获取 300787.SZ 的数据\n", + "成功获取 300788.SZ 的数据\n", + "成功获取 300789.SZ 的数据\n", + "成功获取 300790.SZ 的数据\n", + "成功获取 300791.SZ 的数据\n", + "成功获取 300792.SZ 的数据\n", + "成功获取 300793.SZ 的数据\n", + "成功获取 300795.SZ 的数据\n", + "成功获取 300796.SZ 的数据\n", + "成功获取 300797.SZ 的数据\n", + "成功获取 300798.SZ 的数据\n", + "成功获取 300800.SZ 的数据\n", + "成功获取 300801.SZ 的数据\n", + "成功获取 300802.SZ 的数据\n", + "成功获取 300803.SZ 的数据\n", + "成功获取 300804.SZ 的数据\n", + "成功获取 300805.SZ 的数据\n", + "成功获取 300806.SZ 的数据\n", + "成功获取 300807.SZ 的数据\n", + "成功获取 300808.SZ 的数据\n", + "成功获取 300809.SZ 的数据\n", + "成功获取 300810.SZ 的数据\n", + "成功获取 300811.SZ 的数据\n", + "成功获取 300812.SZ 的数据\n", + "成功获取 300813.SZ 的数据\n", + "成功获取 300814.SZ 的数据\n", + "成功获取 300815.SZ 的数据\n", + "成功获取 300816.SZ 的数据\n", + "成功获取 300817.SZ 的数据\n", + "成功获取 300818.SZ 的数据\n", + "成功获取 300819.SZ 的数据\n", + "成功获取 300820.SZ 的数据\n", + "成功获取 300821.SZ 的数据\n", + "成功获取 300822.SZ 的数据\n", + "成功获取 300823.SZ 的数据\n", + "成功获取 300824.SZ 的数据\n", + "成功获取 300825.SZ 的数据\n", + "成功获取 300826.SZ 的数据\n", + "成功获取 300827.SZ 的数据\n", + "成功获取 300828.SZ 的数据\n", + "成功获取 300829.SZ 的数据\n", + "成功获取 300830.SZ 的数据\n", + "成功获取 300831.SZ 的数据\n", + "成功获取 300832.SZ 的数据\n", + "成功获取 300833.SZ 的数据\n", + "成功获取 300834.SZ 的数据\n", + "成功获取 300835.SZ 的数据\n", + "成功获取 300836.SZ 的数据\n", + "成功获取 300837.SZ 的数据\n", + "成功获取 300838.SZ 的数据\n", + "成功获取 300839.SZ 的数据\n", + "成功获取 300840.SZ 的数据\n", + "成功获取 300841.SZ 的数据\n", + "成功获取 300842.SZ 的数据\n", + "成功获取 300843.SZ 的数据\n", + "成功获取 300844.SZ 的数据\n", + "成功获取 300845.SZ 的数据\n", + "成功获取 300846.SZ 的数据\n", + "成功获取 300847.SZ 的数据\n", + "成功获取 300848.SZ 的数据\n", + "成功获取 300849.SZ 的数据\n", + "成功获取 300850.SZ 的数据\n", + "成功获取 300851.SZ 的数据\n", + "成功获取 300852.SZ 的数据\n", + "成功获取 300853.SZ 的数据\n", + "成功获取 300854.SZ 的数据\n", + "成功获取 300855.SZ 的数据\n", + "成功获取 300856.SZ 的数据\n", + "成功获取 300857.SZ 的数据\n", + "成功获取 300858.SZ 的数据\n", + "成功获取 300859.SZ 的数据\n", + "成功获取 300860.SZ 的数据\n", + "成功获取 300861.SZ 的数据\n", + "成功获取 300862.SZ 的数据\n", + "成功获取 300863.SZ 的数据\n", + "成功获取 300864.SZ 的数据\n", + "成功获取 300865.SZ 的数据\n", + "成功获取 300866.SZ 的数据\n", + "成功获取 300867.SZ 的数据\n", + "成功获取 300868.SZ 的数据\n", + "成功获取 300869.SZ 的数据\n", + "成功获取 300870.SZ 的数据\n", + "成功获取 300871.SZ 的数据\n", + "成功获取 300872.SZ 的数据\n", + "成功获取 300873.SZ 的数据\n", + "成功获取 300875.SZ 的数据\n", + "成功获取 300876.SZ 的数据\n", + "成功获取 300877.SZ 的数据\n", + "成功获取 300878.SZ 的数据\n", + "成功获取 300879.SZ 的数据\n", + "成功获取 300880.SZ 的数据\n", + "成功获取 300881.SZ 的数据\n", + "成功获取 300882.SZ 的数据\n", + "成功获取 300883.SZ 的数据\n", + "成功获取 300884.SZ 的数据\n", + "成功获取 300885.SZ 的数据\n", + "成功获取 300886.SZ 的数据\n", + "成功获取 300887.SZ 的数据\n", + "成功获取 300888.SZ 的数据\n", + "成功获取 300889.SZ 的数据\n", + "成功获取 300890.SZ 的数据\n", + "成功获取 300891.SZ 的数据\n", + "成功获取 300892.SZ 的数据\n", + "成功获取 300893.SZ 的数据\n", + "成功获取 300894.SZ 的数据\n", + "成功获取 300895.SZ 的数据\n", + "成功获取 300896.SZ 的数据\n", + "成功获取 300897.SZ 的数据\n", + "成功获取 300898.SZ 的数据\n", + "成功获取 300899.SZ 的数据\n", + "成功获取 300900.SZ 的数据\n", + "成功获取 300901.SZ 的数据\n", + "成功获取 300902.SZ 的数据\n", + "成功获取 300903.SZ 的数据\n", + "成功获取 300904.SZ 的数据\n", + "成功获取 300905.SZ 的数据\n", + "成功获取 300906.SZ 的数据\n", + "成功获取 300907.SZ 的数据\n", + "成功获取 300908.SZ 的数据\n", + "成功获取 300909.SZ 的数据\n", + "成功获取 300910.SZ 的数据\n", + "成功获取 300911.SZ 的数据\n", + "成功获取 300912.SZ 的数据\n", + "成功获取 300913.SZ 的数据\n", + "成功获取 300915.SZ 的数据\n", + "成功获取 300916.SZ 的数据\n", + "成功获取 300917.SZ 的数据\n", + "成功获取 300918.SZ 的数据\n", + "成功获取 300919.SZ 的数据\n", + "成功获取 300920.SZ 的数据\n", + "成功获取 300921.SZ 的数据\n", + "成功获取 300922.SZ 的数据\n", + "成功获取 300923.SZ 的数据\n", + "成功获取 300925.SZ 的数据\n", + "成功获取 300926.SZ 的数据\n", + "成功获取 300927.SZ 的数据\n", + "成功获取 300928.SZ 的数据\n", + "成功获取 300929.SZ 的数据\n", + "成功获取 300930.SZ 的数据\n", + "成功获取 300931.SZ 的数据\n", + "成功获取 300932.SZ 的数据\n", + "成功获取 300933.SZ 的数据\n", + "成功获取 300935.SZ 的数据\n", + "成功获取 300936.SZ 的数据\n", + "成功获取 300937.SZ 的数据\n", + "成功获取 300938.SZ 的数据\n", + "成功获取 300939.SZ 的数据\n", + "成功获取 300940.SZ 的数据\n", + "成功获取 300941.SZ 的数据\n", + "成功获取 300942.SZ 的数据\n", + "成功获取 300943.SZ 的数据\n", + "成功获取 300945.SZ 的数据\n", + "成功获取 300946.SZ 的数据\n", + "成功获取 300947.SZ 的数据\n", + "成功获取 300948.SZ 的数据\n", + "成功获取 300949.SZ 的数据\n", + "成功获取 300950.SZ 的数据\n", + "成功获取 300951.SZ 的数据\n", + "成功获取 300952.SZ 的数据\n", + "成功获取 300953.SZ 的数据\n", + "成功获取 300955.SZ 的数据\n", + "成功获取 300956.SZ 的数据\n", + "成功获取 300957.SZ 的数据\n", + "成功获取 300958.SZ 的数据\n", + "成功获取 300959.SZ 的数据\n", + "成功获取 300960.SZ 的数据\n", + "成功获取 300961.SZ 的数据\n", + "成功获取 300962.SZ 的数据\n", + "成功获取 300963.SZ 的数据\n", + "成功获取 300964.SZ 的数据\n", + "成功获取 300965.SZ 的数据\n", + "成功获取 300966.SZ 的数据\n", + "成功获取 300967.SZ 的数据\n", + "成功获取 300968.SZ 的数据\n", + "已调用300次API,等待 9.85 秒以满足速率限制...\n", + "成功获取 300969.SZ 的数据\n", + "成功获取 300970.SZ 的数据\n", + "成功获取 300971.SZ 的数据\n", + "成功获取 300972.SZ 的数据\n", + "成功获取 300973.SZ 的数据\n", + "成功获取 300975.SZ 的数据\n", + "成功获取 300976.SZ 的数据\n", + "成功获取 300977.SZ 的数据\n", + "成功获取 300978.SZ 的数据\n", + "成功获取 300979.SZ 的数据\n", + "成功获取 300980.SZ 的数据\n", + "成功获取 300981.SZ 的数据\n", + "成功获取 300982.SZ 的数据\n", + "成功获取 300983.SZ 的数据\n", + "成功获取 300984.SZ 的数据\n", + "成功获取 300985.SZ 的数据\n", + "成功获取 300986.SZ 的数据\n", + "成功获取 300987.SZ 的数据\n", + "成功获取 300988.SZ 的数据\n", + "成功获取 300989.SZ 的数据\n", + "成功获取 300990.SZ 的数据\n", + "成功获取 300991.SZ 的数据\n", + "成功获取 300992.SZ 的数据\n", + "成功获取 300993.SZ 的数据\n", + "成功获取 300994.SZ 的数据\n", + "成功获取 300995.SZ 的数据\n", + "成功获取 300996.SZ 的数据\n", + "成功获取 300997.SZ 的数据\n", + "成功获取 300998.SZ 的数据\n", + "成功获取 300999.SZ 的数据\n", + "成功获取 301000.SZ 的数据\n", + "成功获取 301001.SZ 的数据\n", + "成功获取 301002.SZ 的数据\n", + "成功获取 301003.SZ 的数据\n", + "成功获取 301004.SZ 的数据\n", + "成功获取 301005.SZ 的数据\n", + "成功获取 301006.SZ 的数据\n", + "成功获取 301007.SZ 的数据\n", + "成功获取 301008.SZ 的数据\n", + "成功获取 301009.SZ 的数据\n", + "成功获取 301010.SZ 的数据\n", + "成功获取 301011.SZ 的数据\n", + "成功获取 301012.SZ 的数据\n", + "成功获取 301013.SZ 的数据\n", + "成功获取 301015.SZ 的数据\n", + "成功获取 301016.SZ 的数据\n", + "成功获取 301017.SZ 的数据\n", + "成功获取 301018.SZ 的数据\n", + "成功获取 301019.SZ 的数据\n", + "成功获取 301020.SZ 的数据\n", + "成功获取 301021.SZ 的数据\n", + "成功获取 301022.SZ 的数据\n", + "成功获取 301023.SZ 的数据\n", + "成功获取 301024.SZ 的数据\n", + "成功获取 301025.SZ 的数据\n", + "成功获取 301026.SZ 的数据\n", + "成功获取 301027.SZ 的数据\n", + "成功获取 301028.SZ 的数据\n", + "成功获取 301029.SZ 的数据\n", + "成功获取 301030.SZ 的数据\n", + "成功获取 301031.SZ 的数据\n", + "成功获取 301032.SZ 的数据\n", + "成功获取 301033.SZ 的数据\n", + "成功获取 301035.SZ 的数据\n", + "成功获取 301036.SZ 的数据\n", + "成功获取 301037.SZ 的数据\n", + "成功获取 301038.SZ 的数据\n", + "成功获取 301039.SZ 的数据\n", + "成功获取 301040.SZ 的数据\n", + "成功获取 301041.SZ 的数据\n", + "成功获取 301042.SZ 的数据\n", + "成功获取 301043.SZ 的数据\n", + "成功获取 301045.SZ 的数据\n", + "成功获取 301046.SZ 的数据\n", + "成功获取 301047.SZ 的数据\n", + "成功获取 301048.SZ 的数据\n", + "成功获取 301049.SZ 的数据\n", + "成功获取 301050.SZ 的数据\n", + "成功获取 301051.SZ 的数据\n", + "成功获取 301052.SZ 的数据\n", + "成功获取 301053.SZ 的数据\n", + "成功获取 301055.SZ 的数据\n", + "成功获取 301056.SZ 的数据\n", + "成功获取 301057.SZ 的数据\n", + "成功获取 301058.SZ 的数据\n", + "成功获取 301059.SZ 的数据\n", + "成功获取 301060.SZ 的数据\n", + "成功获取 301061.SZ 的数据\n", + "成功获取 301062.SZ 的数据\n", + "成功获取 301063.SZ 的数据\n", + "成功获取 301065.SZ 的数据\n", + "成功获取 301066.SZ 的数据\n", + "成功获取 301067.SZ 的数据\n", + "成功获取 301068.SZ 的数据\n", + "成功获取 301069.SZ 的数据\n", + "成功获取 301070.SZ 的数据\n", + "成功获取 301071.SZ 的数据\n", + "成功获取 301072.SZ 的数据\n", + "成功获取 301073.SZ 的数据\n", + "成功获取 301075.SZ 的数据\n", + "成功获取 301076.SZ 的数据\n", + "成功获取 301077.SZ 的数据\n", + "成功获取 301078.SZ 的数据\n", + "成功获取 301079.SZ 的数据\n", + "成功获取 301080.SZ 的数据\n", + "成功获取 301081.SZ 的数据\n", + "成功获取 301082.SZ 的数据\n", + "成功获取 301083.SZ 的数据\n", + "成功获取 301085.SZ 的数据\n", + "成功获取 301086.SZ 的数据\n", + "成功获取 301087.SZ 的数据\n", + "成功获取 301088.SZ 的数据\n", + "成功获取 301089.SZ 的数据\n", + "成功获取 301090.SZ 的数据\n", + "成功获取 301091.SZ 的数据\n", + "成功获取 301092.SZ 的数据\n", + "成功获取 301093.SZ 的数据\n", + "成功获取 301095.SZ 的数据\n", + "成功获取 301096.SZ 的数据\n", + "成功获取 301097.SZ 的数据\n", + "成功获取 301098.SZ 的数据\n", + "成功获取 301099.SZ 的数据\n", + "成功获取 301100.SZ 的数据\n", + "成功获取 301101.SZ 的数据\n", + "成功获取 301102.SZ 的数据\n", + "成功获取 301103.SZ 的数据\n", + "成功获取 301105.SZ 的数据\n", + "成功获取 301106.SZ 的数据\n", + "成功获取 301107.SZ 的数据\n", + "成功获取 301108.SZ 的数据\n", + "成功获取 301109.SZ 的数据\n", + "成功获取 301110.SZ 的数据\n", + "成功获取 301111.SZ 的数据\n", + "成功获取 301112.SZ 的数据\n", + "成功获取 301113.SZ 的数据\n", + "成功获取 301115.SZ 的数据\n", + "成功获取 301116.SZ 的数据\n", + "成功获取 301117.SZ 的数据\n", + "成功获取 301118.SZ 的数据\n", + "成功获取 301119.SZ 的数据\n", + "成功获取 301120.SZ 的数据\n", + "成功获取 301121.SZ 的数据\n", + "成功获取 301122.SZ 的数据\n", + "成功获取 301123.SZ 的数据\n", + "成功获取 301125.SZ 的数据\n", + "成功获取 301126.SZ 的数据\n", + "成功获取 301127.SZ 的数据\n", + "成功获取 301128.SZ 的数据\n", + "成功获取 301129.SZ 的数据\n", + "成功获取 301130.SZ 的数据\n", + "成功获取 301131.SZ 的数据\n", + "成功获取 301132.SZ 的数据\n", + "成功获取 301133.SZ 的数据\n", + "成功获取 301135.SZ 的数据\n", + "成功获取 301136.SZ 的数据\n", + "成功获取 301137.SZ 的数据\n", + "成功获取 301138.SZ 的数据\n", + "成功获取 301139.SZ 的数据\n", + "成功获取 301141.SZ 的数据\n", + "成功获取 301148.SZ 的数据\n", + "成功获取 301149.SZ 的数据\n", + "成功获取 301150.SZ 的数据\n", + "成功获取 301151.SZ 的数据\n", + "成功获取 301152.SZ 的数据\n", + "成功获取 301153.SZ 的数据\n", + "成功获取 301155.SZ 的数据\n", + "成功获取 301156.SZ 的数据\n", + "成功获取 301157.SZ 的数据\n", + "成功获取 301158.SZ 的数据\n", + "成功获取 301159.SZ 的数据\n", + "成功获取 301160.SZ 的数据\n", + "成功获取 301161.SZ 的数据\n", + "成功获取 301162.SZ 的数据\n", + "成功获取 301163.SZ 的数据\n", + "成功获取 301165.SZ 的数据\n", + "成功获取 301166.SZ 的数据\n", + "成功获取 301167.SZ 的数据\n", + "成功获取 301168.SZ 的数据\n", + "成功获取 301169.SZ 的数据\n", + "成功获取 301170.SZ 的数据\n", + "成功获取 301171.SZ 的数据\n", + "成功获取 301172.SZ 的数据\n", + "成功获取 301175.SZ 的数据\n", + "成功获取 301176.SZ 的数据\n", + "成功获取 301177.SZ 的数据\n", + "成功获取 301178.SZ 的数据\n", + "成功获取 301179.SZ 的数据\n", + "成功获取 301180.SZ 的数据\n", + "成功获取 301181.SZ 的数据\n", + "成功获取 301182.SZ 的数据\n", + "成功获取 301183.SZ 的数据\n", + "成功获取 301185.SZ 的数据\n", + "成功获取 301186.SZ 的数据\n", + "成功获取 301187.SZ 的数据\n", + "成功获取 301188.SZ 的数据\n", + "成功获取 301189.SZ 的数据\n", + "成功获取 301190.SZ 的数据\n", + "成功获取 301191.SZ 的数据\n", + "成功获取 301192.SZ 的数据\n", + "成功获取 301193.SZ 的数据\n", + "成功获取 301195.SZ 的数据\n", + "成功获取 301196.SZ 的数据\n", + "成功获取 301197.SZ 的数据\n", + "成功获取 301198.SZ 的数据\n", + "成功获取 301199.SZ 的数据\n", + "成功获取 301200.SZ 的数据\n", + "成功获取 301201.SZ 的数据\n", + "成功获取 301202.SZ 的数据\n", + "成功获取 301203.SZ 的数据\n", + "成功获取 301205.SZ 的数据\n", + "成功获取 301206.SZ 的数据\n", + "成功获取 301207.SZ 的数据\n", + "成功获取 301208.SZ 的数据\n", + "成功获取 301209.SZ 的数据\n", + "成功获取 301210.SZ 的数据\n", + "成功获取 301211.SZ 的数据\n", + "成功获取 301212.SZ 的数据\n", + "成功获取 301213.SZ 的数据\n", + "成功获取 301215.SZ 的数据\n", + "成功获取 301216.SZ 的数据\n", + "成功获取 301217.SZ 的数据\n", + "成功获取 301218.SZ 的数据\n", + "成功获取 301219.SZ 的数据\n", + "成功获取 301220.SZ 的数据\n", + "成功获取 301221.SZ 的数据\n", + "成功获取 301222.SZ 的数据\n", + "成功获取 301223.SZ 的数据\n", + "成功获取 301225.SZ 的数据\n", + "成功获取 301226.SZ 的数据\n", + "成功获取 301227.SZ 的数据\n", + "成功获取 301228.SZ 的数据\n", + "成功获取 301229.SZ 的数据\n", + "成功获取 301230.SZ 的数据\n", + "成功获取 301231.SZ 的数据\n", + "成功获取 301232.SZ 的数据\n", + "成功获取 301233.SZ 的数据\n", + "成功获取 301234.SZ 的数据\n", + "成功获取 301235.SZ 的数据\n", + "成功获取 301236.SZ 的数据\n", + "成功获取 301237.SZ 的数据\n", + "成功获取 301238.SZ 的数据\n", + "成功获取 301239.SZ 的数据\n", + "成功获取 301246.SZ 的数据\n", + "成功获取 301248.SZ 的数据\n", + "成功获取 301251.SZ 的数据\n", + "成功获取 301252.SZ 的数据\n", + "成功获取 301255.SZ 的数据\n", + "成功获取 301256.SZ 的数据\n", + "成功获取 301257.SZ 的数据\n", + "成功获取 301258.SZ 的数据\n", + "成功获取 301259.SZ 的数据\n", + "成功获取 301260.SZ 的数据\n", + "成功获取 301261.SZ 的数据\n", + "成功获取 301262.SZ 的数据\n", + "成功获取 301263.SZ 的数据\n", + "成功获取 301265.SZ 的数据\n", + "成功获取 301266.SZ 的数据\n", + "成功获取 301267.SZ 的数据\n", + "成功获取 301268.SZ 的数据\n", + "成功获取 301269.SZ 的数据\n", + "成功获取 301270.SZ 的数据\n", + "成功获取 301272.SZ 的数据\n", + "成功获取 301273.SZ 的数据\n", + "成功获取 301276.SZ 的数据\n", + "成功获取 301277.SZ 的数据\n", + "成功获取 301278.SZ 的数据\n", + "成功获取 301279.SZ 的数据\n", + "成功获取 301280.SZ 的数据\n", + "成功获取 301281.SZ 的数据\n", + "成功获取 301282.SZ 的数据\n", + "成功获取 301283.SZ 的数据\n", + "成功获取 301285.SZ 的数据\n", + "成功获取 301286.SZ 的数据\n", + "成功获取 301287.SZ 的数据\n", + "成功获取 301288.SZ 的数据\n", + "成功获取 301289.SZ 的数据\n", + "成功获取 301290.SZ 的数据\n", + "成功获取 301291.SZ 的数据\n", + "成功获取 301292.SZ 的数据\n", + "成功获取 301293.SZ 的数据\n", + "成功获取 301295.SZ 的数据\n", + "成功获取 301296.SZ 的数据\n", + "成功获取 301297.SZ 的数据\n", + "成功获取 301298.SZ 的数据\n", + "成功获取 301299.SZ 的数据\n", + "成功获取 301300.SZ 的数据\n", + "成功获取 301301.SZ 的数据\n", + "成功获取 301302.SZ 的数据\n", + "成功获取 301303.SZ 的数据\n", + "成功获取 301305.SZ 的数据\n", + "成功获取 301306.SZ 的数据\n", + "成功获取 301307.SZ 的数据\n", + "成功获取 301308.SZ 的数据\n", + "成功获取 301309.SZ 的数据\n", + "成功获取 301310.SZ 的数据\n", + "成功获取 301311.SZ 的数据\n", + "成功获取 301312.SZ 的数据\n", + "成功获取 301313.SZ 的数据\n", + "成功获取 301314.SZ 的数据\n", + "成功获取 301315.SZ 的数据\n", + "已调用300次API,等待 11.75 秒以满足速率限制...\n", + "成功获取 301316.SZ 的数据\n", + "成功获取 301317.SZ 的数据\n", + "成功获取 301318.SZ 的数据\n", + "成功获取 301319.SZ 的数据\n", + "成功获取 301320.SZ 的数据\n", + "成功获取 301321.SZ 的数据\n", + "成功获取 301322.SZ 的数据\n", + "成功获取 301323.SZ 的数据\n", + "成功获取 301325.SZ 的数据\n", + "成功获取 301326.SZ 的数据\n", + "成功获取 301327.SZ 的数据\n", + "成功获取 301328.SZ 的数据\n", + "成功获取 301329.SZ 的数据\n", + "成功获取 301330.SZ 的数据\n", + "成功获取 301331.SZ 的数据\n", + "成功获取 301332.SZ 的数据\n", + "成功获取 301333.SZ 的数据\n", + "成功获取 301335.SZ 的数据\n", + "成功获取 301336.SZ 的数据\n", + "成功获取 301337.SZ 的数据\n", + "成功获取 301338.SZ 的数据\n", + "成功获取 301339.SZ 的数据\n", + "成功获取 301345.SZ 的数据\n", + "成功获取 301348.SZ 的数据\n", + "成功获取 301349.SZ 的数据\n", + "成功获取 301353.SZ 的数据\n", + "成功获取 301355.SZ 的数据\n", + "成功获取 301356.SZ 的数据\n", + "成功获取 301357.SZ 的数据\n", + "成功获取 301358.SZ 的数据\n", + "成功获取 301359.SZ 的数据\n", + "成功获取 301360.SZ 的数据\n", + "成功获取 301361.SZ 的数据\n", + "成功获取 301362.SZ 的数据\n", + "成功获取 301363.SZ 的数据\n", + "成功获取 301365.SZ 的数据\n", + "成功获取 301366.SZ 的数据\n", + "成功获取 301367.SZ 的数据\n", + "成功获取 301368.SZ 的数据\n", + "成功获取 301369.SZ 的数据\n", + "成功获取 301370.SZ 的数据\n", + "成功获取 301371.SZ 的数据\n", + "成功获取 301372.SZ 的数据\n", + "成功获取 301373.SZ 的数据\n", + "成功获取 301376.SZ 的数据\n", + "成功获取 301377.SZ 的数据\n", + "成功获取 301378.SZ 的数据\n", + "成功获取 301379.SZ 的数据\n", + "成功获取 301380.SZ 的数据\n", + "成功获取 301381.SZ 的数据\n", + "成功获取 301382.SZ 的数据\n", + "成功获取 301383.SZ 的数据\n", + "成功获取 301386.SZ 的数据\n", + "成功获取 301387.SZ 的数据\n", + "成功获取 301388.SZ 的数据\n", + "成功获取 301389.SZ 的数据\n", + "成功获取 301390.SZ 的数据\n", + "成功获取 301391.SZ 的数据\n", + "成功获取 301392.SZ 的数据\n", + "成功获取 301393.SZ 的数据\n", + "成功获取 301395.SZ 的数据\n", + "成功获取 301396.SZ 的数据\n", + "成功获取 301397.SZ 的数据\n", + "成功获取 301398.SZ 的数据\n", + "成功获取 301399.SZ 的数据\n", + "成功获取 301408.SZ 的数据\n", + "成功获取 301413.SZ 的数据\n", + "成功获取 301418.SZ 的数据\n", + "成功获取 301419.SZ 的数据\n", + "成功获取 301421.SZ 的数据\n", + "成功获取 301428.SZ 的数据\n", + "成功获取 301429.SZ 的数据\n", + "成功获取 301439.SZ 的数据\n", + "成功获取 301446.SZ 的数据\n", + "成功获取 301448.SZ 的数据\n", + "成功获取 301456.SZ 的数据\n", + "成功获取 301458.SZ 的数据\n", + "成功获取 301459.SZ 的数据\n", + "成功获取 301468.SZ 的数据\n", + "成功获取 301469.SZ 的数据\n", + "成功获取 301486.SZ 的数据\n", + "成功获取 301487.SZ 的数据\n", + "成功获取 301488.SZ 的数据\n", + "成功获取 301489.SZ 的数据\n", + "成功获取 301498.SZ 的数据\n", + "成功获取 301499.SZ 的数据\n", + "成功获取 301500.SZ 的数据\n", + "成功获取 301502.SZ 的数据\n", + "成功获取 301503.SZ 的数据\n", + "成功获取 301505.SZ 的数据\n", + "成功获取 301507.SZ 的数据\n", + "成功获取 301508.SZ 的数据\n", + "成功获取 301509.SZ 的数据\n", + "成功获取 301510.SZ 的数据\n", + "成功获取 301511.SZ 的数据\n", + "成功获取 301512.SZ 的数据\n", + "成功获取 301515.SZ 的数据\n", + "成功获取 301516.SZ 的数据\n", + "成功获取 301517.SZ 的数据\n", + "成功获取 301518.SZ 的数据\n", + "成功获取 301519.SZ 的数据\n", + "成功获取 301520.SZ 的数据\n", + "成功获取 301522.SZ 的数据\n", + "成功获取 301525.SZ 的数据\n", + "成功获取 301526.SZ 的数据\n", + "成功获取 301528.SZ 的数据\n", + "成功获取 301529.SZ 的数据\n", + "成功获取 301533.SZ 的数据\n", + "成功获取 301536.SZ 的数据\n", + "成功获取 301538.SZ 的数据\n", + "成功获取 301539.SZ 的数据\n", + "成功获取 301548.SZ 的数据\n", + "成功获取 301550.SZ 的数据\n", + "成功获取 301551.SZ 的数据\n", + "成功获取 301552.SZ 的数据\n", + "成功获取 301555.SZ 的数据\n", + "成功获取 301556.SZ 的数据\n", + "成功获取 301558.SZ 的数据\n", + "成功获取 301559.SZ 的数据\n", + "成功获取 301565.SZ 的数据\n", + "成功获取 301566.SZ 的数据\n", + "成功获取 301567.SZ 的数据\n", + "成功获取 301568.SZ 的数据\n", + "成功获取 301571.SZ 的数据\n", + "成功获取 301577.SZ 的数据\n", + "成功获取 301578.SZ 的数据\n", + "成功获取 301580.SZ 的数据\n", + "成功获取 301581.SZ 的数据\n", + "成功获取 301585.SZ 的数据\n", + "成功获取 301586.SZ 的数据\n", + "成功获取 301587.SZ 的数据\n", + "成功获取 301588.SZ 的数据\n", + "成功获取 301589.SZ 的数据\n", + "成功获取 301591.SZ 的数据\n", + "成功获取 301592.SZ 的数据\n", + "成功获取 301596.SZ 的数据\n", + "成功获取 301598.SZ 的数据\n", + "成功获取 301600.SZ 的数据\n", + "成功获取 301601.SZ 的数据\n", + "成功获取 301602.SZ 的数据\n", + "成功获取 301603.SZ 的数据\n", + "成功获取 301606.SZ 的数据\n", + "成功获取 301607.SZ 的数据\n", + "成功获取 301608.SZ 的数据\n", + "成功获取 301611.SZ 的数据\n", + "成功获取 301613.SZ 的数据\n", + "成功获取 301617.SZ 的数据\n", + "成功获取 301618.SZ 的数据\n", + "成功获取 301622.SZ 的数据\n", + "成功获取 301626.SZ 的数据\n", + "成功获取 301628.SZ 的数据\n", + "成功获取 301631.SZ 的数据\n", + "成功获取 301633.SZ 的数据\n", + "成功获取 430017.BJ 的数据\n", + "成功获取 430047.BJ 的数据\n", + "成功获取 430090.BJ 的数据\n", + "成功获取 430139.BJ 的数据\n", + "成功获取 430198.BJ 的数据\n", + "成功获取 430300.BJ 的数据\n", + "成功获取 430418.BJ 的数据\n", + "成功获取 430425.BJ 的数据\n", + "成功获取 430476.BJ 的数据\n", + "成功获取 430478.BJ 的数据\n", + "成功获取 430489.BJ 的数据\n", + "成功获取 430510.BJ 的数据\n", + "成功获取 430556.BJ 的数据\n", + "成功获取 430564.BJ 的数据\n", + "成功获取 430685.BJ 的数据\n", + "成功获取 430718.BJ 的数据\n", + "成功获取 600000.SH 的数据\n", + "成功获取 600004.SH 的数据\n", + "成功获取 600006.SH 的数据\n", + "成功获取 600007.SH 的数据\n", + "成功获取 600008.SH 的数据\n", + "成功获取 600009.SH 的数据\n", + "成功获取 600010.SH 的数据\n", + "成功获取 600011.SH 的数据\n", + "成功获取 600012.SH 的数据\n", + "成功获取 600015.SH 的数据\n", + "成功获取 600016.SH 的数据\n", + "成功获取 600017.SH 的数据\n", + "成功获取 600018.SH 的数据\n", + "成功获取 600019.SH 的数据\n", + "成功获取 600020.SH 的数据\n", + "成功获取 600021.SH 的数据\n", + "成功获取 600022.SH 的数据\n", + "成功获取 600023.SH 的数据\n", + "成功获取 600025.SH 的数据\n", + "成功获取 600026.SH 的数据\n", + "成功获取 600027.SH 的数据\n", + "成功获取 600028.SH 的数据\n", + "成功获取 600029.SH 的数据\n", + "成功获取 600030.SH 的数据\n", + "成功获取 600031.SH 的数据\n", + "成功获取 600032.SH 的数据\n", + "成功获取 600033.SH 的数据\n", + "成功获取 600035.SH 的数据\n", + "成功获取 600036.SH 的数据\n", + "成功获取 600037.SH 的数据\n", + "成功获取 600038.SH 的数据\n", + "成功获取 600039.SH 的数据\n", + "成功获取 600048.SH 的数据\n", + "成功获取 600050.SH 的数据\n", + "成功获取 600051.SH 的数据\n", + "成功获取 600052.SH 的数据\n", + "成功获取 600053.SH 的数据\n", + "成功获取 600054.SH 的数据\n", + "成功获取 600055.SH 的数据\n", + "成功获取 600056.SH 的数据\n", + "成功获取 600057.SH 的数据\n", + "成功获取 600058.SH 的数据\n", + "成功获取 600059.SH 的数据\n", + "成功获取 600060.SH 的数据\n", + "成功获取 600061.SH 的数据\n", + "成功获取 600062.SH 的数据\n", + "成功获取 600063.SH 的数据\n", + "成功获取 600064.SH 的数据\n", + "成功获取 600066.SH 的数据\n", + "成功获取 600067.SH 的数据\n", + "成功获取 600070.SH 的数据\n", + "成功获取 600071.SH 的数据\n", + "成功获取 600072.SH 的数据\n", + "成功获取 600073.SH 的数据\n", + "成功获取 600075.SH 的数据\n", + "成功获取 600076.SH 的数据\n", + "成功获取 600078.SH 的数据\n", + "成功获取 600079.SH 的数据\n", + "成功获取 600080.SH 的数据\n", + "成功获取 600081.SH 的数据\n", + "成功获取 600082.SH 的数据\n", + "成功获取 600083.SH 的数据\n", + "成功获取 600084.SH 的数据\n", + "成功获取 600085.SH 的数据\n", + "成功获取 600088.SH 的数据\n", + "成功获取 600089.SH 的数据\n", + "成功获取 600094.SH 的数据\n", + "成功获取 600095.SH 的数据\n", + "成功获取 600096.SH 的数据\n", + "成功获取 600097.SH 的数据\n", + "成功获取 600098.SH 的数据\n", + "成功获取 600099.SH 的数据\n", + "成功获取 600100.SH 的数据\n", + "成功获取 600101.SH 的数据\n", + "成功获取 600103.SH 的数据\n", + "成功获取 600104.SH 的数据\n", + "成功获取 600105.SH 的数据\n", + "成功获取 600106.SH 的数据\n", + "成功获取 600107.SH 的数据\n", + "成功获取 600108.SH 的数据\n", + "成功获取 600109.SH 的数据\n", + "成功获取 600110.SH 的数据\n", + "成功获取 600111.SH 的数据\n", + "成功获取 600113.SH 的数据\n", + "成功获取 600114.SH 的数据\n", + "成功获取 600115.SH 的数据\n", + "成功获取 600116.SH 的数据\n", + "成功获取 600117.SH 的数据\n", + "成功获取 600118.SH 的数据\n", + "成功获取 600119.SH 的数据\n", + "成功获取 600120.SH 的数据\n", + "成功获取 600121.SH 的数据\n", + "成功获取 600123.SH 的数据\n", + "成功获取 600125.SH 的数据\n", + "成功获取 600126.SH 的数据\n", + "成功获取 600127.SH 的数据\n", + "成功获取 600128.SH 的数据\n", + "成功获取 600129.SH 的数据\n", + "成功获取 600130.SH 的数据\n", + "成功获取 600131.SH 的数据\n", + "成功获取 600132.SH 的数据\n", + "成功获取 600133.SH 的数据\n", + "成功获取 600135.SH 的数据\n", + "成功获取 600136.SH 的数据\n", + "成功获取 600137.SH 的数据\n", + "成功获取 600138.SH 的数据\n", + "成功获取 600141.SH 的数据\n", + "成功获取 600143.SH 的数据\n", + "成功获取 600148.SH 的数据\n", + "成功获取 600149.SH 的数据\n", + "成功获取 600150.SH 的数据\n", + "成功获取 600151.SH 的数据\n", + "成功获取 600152.SH 的数据\n", + "成功获取 600153.SH 的数据\n", + "成功获取 600155.SH 的数据\n", + "成功获取 600156.SH 的数据\n", + "成功获取 600157.SH 的数据\n", + "成功获取 600158.SH 的数据\n", + "成功获取 600159.SH 的数据\n", + "成功获取 600160.SH 的数据\n", + "成功获取 600161.SH 的数据\n", + "成功获取 600162.SH 的数据\n", + "成功获取 600163.SH 的数据\n", + "成功获取 600165.SH 的数据\n", + "成功获取 600166.SH 的数据\n", + "成功获取 600167.SH 的数据\n", + "成功获取 600168.SH 的数据\n", + "成功获取 600169.SH 的数据\n", + "成功获取 600170.SH 的数据\n", + "成功获取 600171.SH 的数据\n", + "成功获取 600172.SH 的数据\n", + "已调用300次API,等待 5.16 秒以满足速率限制...\n", + "成功获取 600173.SH 的数据\n", + "成功获取 600176.SH 的数据\n", + "成功获取 600177.SH 的数据\n", + "成功获取 600178.SH 的数据\n", + "成功获取 600179.SH 的数据\n", + "成功获取 600180.SH 的数据\n", + "成功获取 600182.SH 的数据\n", + "成功获取 600183.SH 的数据\n", + "成功获取 600184.SH 的数据\n", + "成功获取 600185.SH 的数据\n", + "成功获取 600186.SH 的数据\n", + "成功获取 600187.SH 的数据\n", + "成功获取 600188.SH 的数据\n", + "成功获取 600189.SH 的数据\n", + "成功获取 600190.SH 的数据\n", + "成功获取 600191.SH 的数据\n", + "成功获取 600192.SH 的数据\n", + "成功获取 600193.SH 的数据\n", + "成功获取 600195.SH 的数据\n", + "成功获取 600196.SH 的数据\n", + "成功获取 600197.SH 的数据\n", + "成功获取 600198.SH 的数据\n", + "成功获取 600199.SH 的数据\n", + "成功获取 600200.SH 的数据\n", + "成功获取 600201.SH 的数据\n", + "成功获取 600202.SH 的数据\n", + "成功获取 600203.SH 的数据\n", + "成功获取 600206.SH 的数据\n", + "成功获取 600207.SH 的数据\n", + "成功获取 600208.SH 的数据\n", + "成功获取 600210.SH 的数据\n", + "成功获取 600211.SH 的数据\n", + "成功获取 600212.SH 的数据\n", + "成功获取 600215.SH 的数据\n", + "成功获取 600216.SH 的数据\n", + "成功获取 600217.SH 的数据\n", + "成功获取 600218.SH 的数据\n", + "成功获取 600219.SH 的数据\n", + "成功获取 600221.SH 的数据\n", + "成功获取 600222.SH 的数据\n", + "成功获取 600223.SH 的数据\n", + "成功获取 600225.SH 的数据\n", + "成功获取 600226.SH 的数据\n", + "成功获取 600227.SH 的数据\n", + "成功获取 600228.SH 的数据\n", + "成功获取 600229.SH 的数据\n", + "成功获取 600230.SH 的数据\n", + "成功获取 600231.SH 的数据\n", + "成功获取 600232.SH 的数据\n", + "成功获取 600233.SH 的数据\n", + "成功获取 600234.SH 的数据\n", + "成功获取 600235.SH 的数据\n", + "成功获取 600236.SH 的数据\n", + "成功获取 600237.SH 的数据\n", + "成功获取 600238.SH 的数据\n", + "成功获取 600239.SH 的数据\n", + "成功获取 600241.SH 的数据\n", + "成功获取 600243.SH 的数据\n", + "成功获取 600246.SH 的数据\n", + "成功获取 600248.SH 的数据\n", + "成功获取 600249.SH 的数据\n", + "成功获取 600250.SH 的数据\n", + "成功获取 600251.SH 的数据\n", + "成功获取 600252.SH 的数据\n", + "成功获取 600255.SH 的数据\n", + "成功获取 600256.SH 的数据\n", + "成功获取 600257.SH 的数据\n", + "成功获取 600258.SH 的数据\n", + "成功获取 600259.SH 的数据\n", + "成功获取 600261.SH 的数据\n", + "成功获取 600262.SH 的数据\n", + "成功获取 600265.SH 的数据\n", + "成功获取 600266.SH 的数据\n", + "成功获取 600267.SH 的数据\n", + "成功获取 600268.SH 的数据\n", + "成功获取 600269.SH 的数据\n", + "成功获取 600271.SH 的数据\n", + "成功获取 600272.SH 的数据\n", + "成功获取 600273.SH 的数据\n", + "成功获取 600276.SH 的数据\n", + "成功获取 600278.SH 的数据\n", + "成功获取 600279.SH 的数据\n", + "成功获取 600280.SH 的数据\n", + "成功获取 600281.SH 的数据\n", + "成功获取 600282.SH 的数据\n", + "成功获取 600283.SH 的数据\n", + "成功获取 600284.SH 的数据\n", + "成功获取 600285.SH 的数据\n", + "成功获取 600287.SH 的数据\n", + "成功获取 600288.SH 的数据\n", + "成功获取 600289.SH 的数据\n", + "成功获取 600292.SH 的数据\n", + "成功获取 600293.SH 的数据\n", + "成功获取 600295.SH 的数据\n", + "成功获取 600298.SH 的数据\n", + "成功获取 600299.SH 的数据\n", + "成功获取 600300.SH 的数据\n", + "成功获取 600301.SH 的数据\n", + "成功获取 600302.SH 的数据\n", + "成功获取 600303.SH 的数据\n", + "成功获取 600305.SH 的数据\n", + "成功获取 600307.SH 的数据\n", + "成功获取 600308.SH 的数据\n", + "成功获取 600309.SH 的数据\n", + "成功获取 600310.SH 的数据\n", + "成功获取 600312.SH 的数据\n", + "成功获取 600313.SH 的数据\n", + "成功获取 600315.SH 的数据\n", + "成功获取 600316.SH 的数据\n", + "成功获取 600318.SH 的数据\n", + "成功获取 600319.SH 的数据\n", + "成功获取 600320.SH 的数据\n", + "成功获取 600322.SH 的数据\n", + "成功获取 600323.SH 的数据\n", + "成功获取 600325.SH 的数据\n", + "成功获取 600326.SH 的数据\n", + "成功获取 600327.SH 的数据\n", + "成功获取 600328.SH 的数据\n", + "成功获取 600329.SH 的数据\n", + "成功获取 600330.SH 的数据\n", + "成功获取 600331.SH 的数据\n", + "成功获取 600332.SH 的数据\n", + "成功获取 600333.SH 的数据\n", + "成功获取 600335.SH 的数据\n", + "成功获取 600336.SH 的数据\n", + "成功获取 600337.SH 的数据\n", + "成功获取 600338.SH 的数据\n", + "成功获取 600339.SH 的数据\n", + "成功获取 600340.SH 的数据\n", + "成功获取 600343.SH 的数据\n", + "成功获取 600345.SH 的数据\n", + "成功获取 600346.SH 的数据\n", + "成功获取 600348.SH 的数据\n", + "成功获取 600350.SH 的数据\n", + "成功获取 600351.SH 的数据\n", + "成功获取 600352.SH 的数据\n", + "成功获取 600353.SH 的数据\n", + "成功获取 600354.SH 的数据\n", + "成功获取 600355.SH 的数据\n", + "成功获取 600356.SH 的数据\n", + "成功获取 600358.SH 的数据\n", + "成功获取 600359.SH 的数据\n", + "成功获取 600360.SH 的数据\n", + "成功获取 600361.SH 的数据\n", + "成功获取 600362.SH 的数据\n", + "成功获取 600363.SH 的数据\n", + "成功获取 600365.SH 的数据\n", + "成功获取 600366.SH 的数据\n", + "成功获取 600367.SH 的数据\n", + "成功获取 600368.SH 的数据\n", + "成功获取 600369.SH 的数据\n", + "成功获取 600370.SH 的数据\n", + "成功获取 600371.SH 的数据\n", + "成功获取 600372.SH 的数据\n", + "成功获取 600373.SH 的数据\n", + "成功获取 600375.SH 的数据\n", + "成功获取 600376.SH 的数据\n", + "成功获取 600377.SH 的数据\n", + "成功获取 600378.SH 的数据\n", + "成功获取 600379.SH 的数据\n", + "成功获取 600380.SH 的数据\n", + "成功获取 600381.SH 的数据\n", + "成功获取 600382.SH 的数据\n", + "成功获取 600383.SH 的数据\n", + "成功获取 600386.SH 的数据\n", + "成功获取 600387.SH 的数据\n", + "成功获取 600388.SH 的数据\n", + "成功获取 600389.SH 的数据\n", + "成功获取 600390.SH 的数据\n", + "成功获取 600391.SH 的数据\n", + "成功获取 600392.SH 的数据\n", + "成功获取 600395.SH 的数据\n", + "成功获取 600396.SH 的数据\n", + "成功获取 600397.SH 的数据\n", + "成功获取 600398.SH 的数据\n", + "成功获取 600399.SH 的数据\n", + "成功获取 600400.SH 的数据\n", + "成功获取 600403.SH 的数据\n", + "成功获取 600405.SH 的数据\n", + "成功获取 600406.SH 的数据\n", + "成功获取 600408.SH 的数据\n", + "成功获取 600409.SH 的数据\n", + "成功获取 600410.SH 的数据\n", + "成功获取 600415.SH 的数据\n", + "成功获取 600416.SH 的数据\n", + "成功获取 600418.SH 的数据\n", + "成功获取 600419.SH 的数据\n", + "成功获取 600420.SH 的数据\n", + "成功获取 600421.SH 的数据\n", + "成功获取 600422.SH 的数据\n", + "成功获取 600423.SH 的数据\n", + "成功获取 600425.SH 的数据\n", + "成功获取 600426.SH 的数据\n", + "成功获取 600428.SH 的数据\n", + "成功获取 600429.SH 的数据\n", + "成功获取 600433.SH 的数据\n", + "成功获取 600435.SH 的数据\n", + "成功获取 600436.SH 的数据\n", + "成功获取 600438.SH 的数据\n", + "成功获取 600439.SH 的数据\n", + "成功获取 600444.SH 的数据\n", + "成功获取 600446.SH 的数据\n", + "成功获取 600448.SH 的数据\n", + "成功获取 600449.SH 的数据\n", + "成功获取 600452.SH 的数据\n", + "成功获取 600455.SH 的数据\n", + "成功获取 600456.SH 的数据\n", + "成功获取 600458.SH 的数据\n", + "成功获取 600459.SH 的数据\n", + "成功获取 600460.SH 的数据\n", + "成功获取 600461.SH 的数据\n", + "成功获取 600462.SH 的数据\n", + "成功获取 600463.SH 的数据\n", + "成功获取 600467.SH 的数据\n", + "成功获取 600468.SH 的数据\n", + "成功获取 600469.SH 的数据\n", + "成功获取 600470.SH 的数据\n", + "成功获取 600475.SH 的数据\n", + "成功获取 600476.SH 的数据\n", + "成功获取 600477.SH 的数据\n", + "成功获取 600478.SH 的数据\n", + "成功获取 600479.SH 的数据\n", + "成功获取 600480.SH 的数据\n", + "成功获取 600481.SH 的数据\n", + "成功获取 600482.SH 的数据\n", + "成功获取 600483.SH 的数据\n", + "成功获取 600486.SH 的数据\n", + "成功获取 600487.SH 的数据\n", + "成功获取 600488.SH 的数据\n", + "成功获取 600489.SH 的数据\n", + "成功获取 600490.SH 的数据\n", + "成功获取 600491.SH 的数据\n", + "成功获取 600493.SH 的数据\n", + "成功获取 600495.SH 的数据\n", + "成功获取 600496.SH 的数据\n", + "成功获取 600497.SH 的数据\n", + "成功获取 600498.SH 的数据\n", + "成功获取 600499.SH 的数据\n", + "成功获取 600500.SH 的数据\n", + "成功获取 600501.SH 的数据\n", + "成功获取 600502.SH 的数据\n", + "成功获取 600503.SH 的数据\n", + "成功获取 600505.SH 的数据\n", + "成功获取 600506.SH 的数据\n", + "成功获取 600507.SH 的数据\n", + "成功获取 600508.SH 的数据\n", + "成功获取 600509.SH 的数据\n", + "成功获取 600510.SH 的数据\n", + "成功获取 600511.SH 的数据\n", + "成功获取 600512.SH 的数据\n", + "成功获取 600513.SH 的数据\n", + "成功获取 600515.SH 的数据\n", + "成功获取 600516.SH 的数据\n", + "成功获取 600517.SH 的数据\n", + "成功获取 600518.SH 的数据\n", + "成功获取 600519.SH 的数据\n", + "成功获取 600520.SH 的数据\n", + "成功获取 600521.SH 的数据\n", + "成功获取 600522.SH 的数据\n", + "成功获取 600523.SH 的数据\n", + "成功获取 600525.SH 的数据\n", + "成功获取 600526.SH 的数据\n", + "成功获取 600527.SH 的数据\n", + "成功获取 600528.SH 的数据\n", + "成功获取 600529.SH 的数据\n", + "成功获取 600530.SH 的数据\n", + "成功获取 600531.SH 的数据\n", + "成功获取 600533.SH 的数据\n", + "成功获取 600535.SH 的数据\n", + "成功获取 600536.SH 的数据\n", + "成功获取 600537.SH 的数据\n", + "成功获取 600538.SH 的数据\n", + "成功获取 600539.SH 的数据\n", + "成功获取 600540.SH 的数据\n", + "成功获取 600543.SH 的数据\n", + "成功获取 600545.SH 的数据\n", + "成功获取 600546.SH 的数据\n", + "成功获取 600547.SH 的数据\n", + "成功获取 600548.SH 的数据\n", + "成功获取 600549.SH 的数据\n", + "成功获取 600550.SH 的数据\n", + "成功获取 600551.SH 的数据\n", + "成功获取 600552.SH 的数据\n", + "成功获取 600556.SH 的数据\n", + "成功获取 600557.SH 的数据\n", + "成功获取 600558.SH 的数据\n", + "成功获取 600559.SH 的数据\n", + "成功获取 600560.SH 的数据\n", + "成功获取 600561.SH 的数据\n", + "成功获取 600562.SH 的数据\n", + "成功获取 600563.SH 的数据\n", + "成功获取 600566.SH 的数据\n", + "成功获取 600567.SH 的数据\n", + "成功获取 600568.SH 的数据\n", + "成功获取 600569.SH 的数据\n", + "成功获取 600570.SH 的数据\n", + "成功获取 600571.SH 的数据\n", + "成功获取 600572.SH 的数据\n", + "成功获取 600573.SH 的数据\n", + "成功获取 600575.SH 的数据\n", + "成功获取 600576.SH 的数据\n", + "成功获取 600577.SH 的数据\n", + "成功获取 600578.SH 的数据\n", + "成功获取 600579.SH 的数据\n", + "成功获取 600580.SH 的数据\n", + "成功获取 600581.SH 的数据\n", + "成功获取 600582.SH 的数据\n", + "成功获取 600583.SH 的数据\n", + "成功获取 600584.SH 的数据\n", + "成功获取 600585.SH 的数据\n", + "成功获取 600586.SH 的数据\n", + "成功获取 600587.SH 的数据\n", + "成功获取 600588.SH 的数据\n", + "成功获取 600589.SH 的数据\n", + "成功获取 600590.SH 的数据\n", + "成功获取 600592.SH 的数据\n", + "成功获取 600593.SH 的数据\n", + "成功获取 600594.SH 的数据\n", + "成功获取 600595.SH 的数据\n", + "成功获取 600596.SH 的数据\n", + "成功获取 600597.SH 的数据\n", + "成功获取 600598.SH 的数据\n", + "成功获取 600599.SH 的数据\n", + "成功获取 600600.SH 的数据\n", + "成功获取 600601.SH 的数据\n", + "成功获取 600602.SH 的数据\n", + "成功获取 600603.SH 的数据\n", + "成功获取 600604.SH 的数据\n", + "成功获取 600605.SH 的数据\n", + "成功获取 600606.SH 的数据\n", + "成功获取 600608.SH 的数据\n", + "成功获取 600609.SH 的数据\n", + "成功获取 600610.SH 的数据\n", + "成功获取 600611.SH 的数据\n", + "成功获取 600612.SH 的数据\n", + "成功获取 600613.SH 的数据\n", + "成功获取 600615.SH 的数据\n", + "成功获取 600616.SH 的数据\n", + "成功获取 600617.SH 的数据\n", + "成功获取 600618.SH 的数据\n", + "成功获取 600619.SH 的数据\n", + "成功获取 600620.SH 的数据\n", + "成功获取 600621.SH 的数据\n", + "成功获取 600622.SH 的数据\n", + "成功获取 600623.SH 的数据\n", + "成功获取 600624.SH 的数据\n", + "成功获取 600626.SH 的数据\n", + "成功获取 600628.SH 的数据\n", + "成功获取 600629.SH 的数据\n", + "成功获取 600630.SH 的数据\n", + "成功获取 600633.SH 的数据\n", + "成功获取 600635.SH 的数据\n", + "成功获取 600636.SH 的数据\n", + "成功获取 600637.SH 的数据\n", + "成功获取 600638.SH 的数据\n", + "成功获取 600639.SH 的数据\n", + "成功获取 600640.SH 的数据\n", + "成功获取 600641.SH 的数据\n", + "成功获取 600642.SH 的数据\n", + "成功获取 600643.SH 的数据\n", + "成功获取 600644.SH 的数据\n", + "成功获取 600645.SH 的数据\n", + "成功获取 600648.SH 的数据\n", + "成功获取 600649.SH 的数据\n", + "成功获取 600650.SH 的数据\n", + "成功获取 600651.SH 的数据\n", + "成功获取 600653.SH 的数据\n", + "成功获取 600654.SH 的数据\n", + "成功获取 600655.SH 的数据\n", + "成功获取 600657.SH 的数据\n", + "成功获取 600658.SH 的数据\n", + "成功获取 600660.SH 的数据\n", + "成功获取 600661.SH 的数据\n", + "成功获取 600662.SH 的数据\n", + "成功获取 600663.SH 的数据\n", + "成功获取 600664.SH 的数据\n", + "成功获取 600665.SH 的数据\n", + "成功获取 600666.SH 的数据\n", + "成功获取 600667.SH 的数据\n", + "成功获取 600668.SH 的数据\n", + "成功获取 600671.SH 的数据\n", + "成功获取 600673.SH 的数据\n", + "成功获取 600674.SH 的数据\n", + "成功获取 600675.SH 的数据\n", + "成功获取 600676.SH 的数据\n", + "成功获取 600678.SH 的数据\n", + "成功获取 600679.SH 的数据\n", + "成功获取 600681.SH 的数据\n", + "成功获取 600682.SH 的数据\n", + "成功获取 600683.SH 的数据\n", + "成功获取 600684.SH 的数据\n", + "成功获取 600685.SH 的数据\n", + "成功获取 600686.SH 的数据\n", + "成功获取 600688.SH 的数据\n", + "成功获取 600689.SH 的数据\n", + "成功获取 600690.SH 的数据\n", + "成功获取 600691.SH 的数据\n", + "成功获取 600692.SH 的数据\n", + "成功获取 600693.SH 的数据\n", + "成功获取 600694.SH 的数据\n", + "成功获取 600696.SH 的数据\n", + "成功获取 600697.SH 的数据\n", + "成功获取 600698.SH 的数据\n", + "成功获取 600699.SH 的数据\n", + "成功获取 600702.SH 的数据\n", + "成功获取 600703.SH 的数据\n", + "成功获取 600704.SH 的数据\n", + "成功获取 600705.SH 的数据\n", + "成功获取 600706.SH 的数据\n", + "成功获取 600707.SH 的数据\n", + "成功获取 600708.SH 的数据\n", + "成功获取 600710.SH 的数据\n", + "成功获取 600711.SH 的数据\n", + "成功获取 600712.SH 的数据\n", + "成功获取 600713.SH 的数据\n", + "成功获取 600714.SH 的数据\n", + "成功获取 600715.SH 的数据\n", + "成功获取 600716.SH 的数据\n", + "成功获取 600717.SH 的数据\n", + "成功获取 600718.SH 的数据\n", + "成功获取 600719.SH 的数据\n", + "成功获取 600720.SH 的数据\n", + "成功获取 600721.SH 的数据\n", + "成功获取 600722.SH 的数据\n", + "成功获取 600724.SH 的数据\n", + "成功获取 600725.SH 的数据\n", + "成功获取 600726.SH 的数据\n", + "成功获取 600727.SH 的数据\n", + "成功获取 600728.SH 的数据\n", + "成功获取 600729.SH 的数据\n", + "成功获取 600730.SH 的数据\n", + "成功获取 600731.SH 的数据\n", + "成功获取 600732.SH 的数据\n", + "成功获取 600733.SH 的数据\n", + "成功获取 600734.SH 的数据\n", + "成功获取 600735.SH 的数据\n", + "成功获取 600736.SH 的数据\n", + "成功获取 600737.SH 的数据\n", + "成功获取 600738.SH 的数据\n", + "成功获取 600739.SH 的数据\n", + "成功获取 600740.SH 的数据\n", + "成功获取 600741.SH 的数据\n", + "成功获取 600742.SH 的数据\n", + "成功获取 600743.SH 的数据\n", + "成功获取 600744.SH 的数据\n", + "成功获取 600745.SH 的数据\n", + "成功获取 600746.SH 的数据\n", + "成功获取 600748.SH 的数据\n", + "成功获取 600749.SH 的数据\n", + "成功获取 600750.SH 的数据\n", + "成功获取 600751.SH 的数据\n", + "成功获取 600753.SH 的数据\n", + "成功获取 600754.SH 的数据\n", + "成功获取 600755.SH 的数据\n", + "成功获取 600756.SH 的数据\n", + "成功获取 600757.SH 的数据\n", + "成功获取 600758.SH 的数据\n", + "成功获取 600759.SH 的数据\n", + "成功获取 600760.SH 的数据\n", + "成功获取 600761.SH 的数据\n", + "成功获取 600763.SH 的数据\n", + "成功获取 600764.SH 的数据\n", + "成功获取 600765.SH 的数据\n", + "成功获取 600768.SH 的数据\n", + "成功获取 600769.SH 的数据\n", + "成功获取 600770.SH 的数据\n", + "成功获取 600771.SH 的数据\n", + "成功获取 600773.SH 的数据\n", + "成功获取 600774.SH 的数据\n", + "成功获取 600775.SH 的数据\n", + "成功获取 600776.SH 的数据\n", + "成功获取 600777.SH 的数据\n", + "成功获取 600778.SH 的数据\n", + "成功获取 600779.SH 的数据\n", + "成功获取 600780.SH 的数据\n", + "成功获取 600782.SH 的数据\n", + "成功获取 600783.SH 的数据\n", + "成功获取 600784.SH 的数据\n", + "成功获取 600785.SH 的数据\n", + "成功获取 600787.SH 的数据\n", + "成功获取 600789.SH 的数据\n", + "成功获取 600790.SH 的数据\n", + "成功获取 600791.SH 的数据\n", + "成功获取 600792.SH 的数据\n", + "成功获取 600793.SH 的数据\n", + "成功获取 600794.SH 的数据\n", + "成功获取 600795.SH 的数据\n", + "成功获取 600796.SH 的数据\n", + "成功获取 600797.SH 的数据\n", + "成功获取 600798.SH 的数据\n", + "成功获取 600800.SH 的数据\n", + "成功获取 600801.SH 的数据\n", + "成功获取 600802.SH 的数据\n", + "成功获取 600803.SH 的数据\n", + "成功获取 600804.SH 的数据\n", + "成功获取 600805.SH 的数据\n", + "成功获取 600807.SH 的数据\n", + "成功获取 600808.SH 的数据\n", + "成功获取 600809.SH 的数据\n", + "成功获取 600810.SH 的数据\n", + "成功获取 600811.SH 的数据\n", + "成功获取 600812.SH 的数据\n", + "成功获取 600814.SH 的数据\n", + "成功获取 600815.SH 的数据\n", + "成功获取 600816.SH 的数据\n", + "成功获取 600817.SH 的数据\n", + "成功获取 600818.SH 的数据\n", + "成功获取 600819.SH 的数据\n", + "成功获取 600820.SH 的数据\n", + "成功获取 600821.SH 的数据\n", + "成功获取 600822.SH 的数据\n", + "成功获取 600824.SH 的数据\n", + "成功获取 600825.SH 的数据\n", + "成功获取 600826.SH 的数据\n", + "成功获取 600827.SH 的数据\n", + "成功获取 600828.SH 的数据\n", + "成功获取 600829.SH 的数据\n", + "成功获取 600830.SH 的数据\n", + "成功获取 600831.SH 的数据\n", + "成功获取 600833.SH 的数据\n", + "成功获取 600834.SH 的数据\n", + "成功获取 600835.SH 的数据\n", + "成功获取 600837.SH 的数据\n", + "成功获取 600838.SH 的数据\n", + "成功获取 600839.SH 的数据\n", + "成功获取 600841.SH 的数据\n", + "成功获取 600843.SH 的数据\n", + "成功获取 600844.SH 的数据\n", + "成功获取 600845.SH 的数据\n", + "成功获取 600846.SH 的数据\n", + "成功获取 600847.SH 的数据\n", + "成功获取 600848.SH 的数据\n", + "成功获取 600850.SH 的数据\n", + "成功获取 600851.SH 的数据\n", + "成功获取 600853.SH 的数据\n", + "成功获取 600854.SH 的数据\n", + "成功获取 600855.SH 的数据\n", + "成功获取 600857.SH 的数据\n", + "成功获取 600858.SH 的数据\n", + "成功获取 600859.SH 的数据\n", + "成功获取 600860.SH 的数据\n", + "成功获取 600861.SH 的数据\n", + "成功获取 600862.SH 的数据\n", + "成功获取 600863.SH 的数据\n", + "成功获取 600864.SH 的数据\n", + "成功获取 600865.SH 的数据\n", + "成功获取 600866.SH 的数据\n", + "成功获取 600867.SH 的数据\n", + "成功获取 600868.SH 的数据\n", + "成功获取 600869.SH 的数据\n", + "成功获取 600871.SH 的数据\n", + "成功获取 600872.SH 的数据\n", + "成功获取 600873.SH 的数据\n", + "成功获取 600874.SH 的数据\n", + "成功获取 600875.SH 的数据\n", + "成功获取 600876.SH 的数据\n", + "成功获取 600877.SH 的数据\n", + "成功获取 600879.SH 的数据\n", + "成功获取 600880.SH 的数据\n", + "成功获取 600881.SH 的数据\n", + "成功获取 600882.SH 的数据\n", + "成功获取 600883.SH 的数据\n", + "成功获取 600884.SH 的数据\n", + "成功获取 600885.SH 的数据\n", + "成功获取 600886.SH 的数据\n", + "成功获取 600887.SH 的数据\n", + "成功获取 600888.SH 的数据\n", + "成功获取 600889.SH 的数据\n", + "成功获取 600892.SH 的数据\n", + "成功获取 600893.SH 的数据\n", + "成功获取 600894.SH 的数据\n", + "成功获取 600895.SH 的数据\n", + "成功获取 600897.SH 的数据\n", + "成功获取 600898.SH 的数据\n", + "成功获取 600900.SH 的数据\n", + "成功获取 600901.SH 的数据\n", + "成功获取 600903.SH 的数据\n", + "成功获取 600905.SH 的数据\n", + "成功获取 600906.SH 的数据\n", + "成功获取 600908.SH 的数据\n", + "成功获取 600909.SH 的数据\n", + "成功获取 600916.SH 的数据\n", + "成功获取 600917.SH 的数据\n", + "成功获取 600918.SH 的数据\n", + "成功获取 600919.SH 的数据\n", + "成功获取 600925.SH 的数据\n", + "成功获取 600926.SH 的数据\n", + "成功获取 600927.SH 的数据\n", + "成功获取 600928.SH 的数据\n", + "成功获取 600929.SH 的数据\n", + "成功获取 600933.SH 的数据\n", + "成功获取 600935.SH 的数据\n", + "成功获取 600936.SH 的数据\n", + "成功获取 600938.SH 的数据\n", + "成功获取 600939.SH 的数据\n", + "成功获取 600941.SH 的数据\n", + "成功获取 600955.SH 的数据\n", + "成功获取 600956.SH 的数据\n", + "成功获取 600958.SH 的数据\n", + "成功获取 600959.SH 的数据\n", + "成功获取 600960.SH 的数据\n", + "成功获取 600961.SH 的数据\n", + "成功获取 600962.SH 的数据\n", + "成功获取 600963.SH 的数据\n", + "成功获取 600965.SH 的数据\n", + "成功获取 600966.SH 的数据\n", + "成功获取 600967.SH 的数据\n", + "成功获取 600968.SH 的数据\n", + "成功获取 600969.SH 的数据\n", + "成功获取 600970.SH 的数据\n", + "成功获取 600971.SH 的数据\n", + "成功获取 600973.SH 的数据\n", + "成功获取 600975.SH 的数据\n", + "成功获取 600976.SH 的数据\n", + "成功获取 600977.SH 的数据\n", + "成功获取 600979.SH 的数据\n", + "成功获取 600980.SH 的数据\n", + "成功获取 600981.SH 的数据\n", + "成功获取 600982.SH 的数据\n", + "成功获取 600983.SH 的数据\n", + "成功获取 600984.SH 的数据\n", + "成功获取 600985.SH 的数据\n", + "成功获取 600986.SH 的数据\n", + "成功获取 600987.SH 的数据\n", + "成功获取 600988.SH 的数据\n", + "成功获取 600989.SH 的数据\n", + "成功获取 600990.SH 的数据\n", + "成功获取 600992.SH 的数据\n", + "成功获取 600993.SH 的数据\n", + "成功获取 600995.SH 的数据\n", + "成功获取 600996.SH 的数据\n", + "成功获取 600997.SH 的数据\n", + "成功获取 600998.SH 的数据\n", + "成功获取 600999.SH 的数据\n", + "成功获取 601000.SH 的数据\n", + "成功获取 601001.SH 的数据\n", + "成功获取 601002.SH 的数据\n", + "成功获取 601003.SH 的数据\n", + "成功获取 601005.SH 的数据\n", + "成功获取 601006.SH 的数据\n", + "成功获取 601007.SH 的数据\n", + "成功获取 601008.SH 的数据\n", + "成功获取 601009.SH 的数据\n", + "成功获取 601010.SH 的数据\n", + "成功获取 601011.SH 的数据\n", + "成功获取 601012.SH 的数据\n", + "成功获取 601015.SH 的数据\n", + "成功获取 601016.SH 的数据\n", + "成功获取 601018.SH 的数据\n", + "成功获取 601019.SH 的数据\n", + "成功获取 601020.SH 的数据\n", + "成功获取 601021.SH 的数据\n", + "成功获取 601022.SH 的数据\n", + "成功获取 601028.SH 的数据\n", + "成功获取 601033.SH 的数据\n", + "成功获取 601038.SH 的数据\n", + "成功获取 601058.SH 的数据\n", + "成功获取 601059.SH 的数据\n", + "成功获取 601061.SH 的数据\n", + "成功获取 601065.SH 的数据\n", + "成功获取 601066.SH 的数据\n", + "成功获取 601068.SH 的数据\n", + "成功获取 601069.SH 的数据\n", + "成功获取 601077.SH 的数据\n", + "成功获取 601083.SH 的数据\n", + "成功获取 601086.SH 的数据\n", + "成功获取 601088.SH 的数据\n", + "成功获取 601089.SH 的数据\n", + "成功获取 601096.SH 的数据\n", + "成功获取 601098.SH 的数据\n", + "成功获取 601099.SH 的数据\n", + "成功获取 601100.SH 的数据\n", + "成功获取 601101.SH 的数据\n", + "成功获取 601106.SH 的数据\n", + "成功获取 601107.SH 的数据\n", + "成功获取 601108.SH 的数据\n", + "成功获取 601111.SH 的数据\n", + "成功获取 601113.SH 的数据\n", + "成功获取 601116.SH 的数据\n", + "成功获取 601117.SH 的数据\n", + "成功获取 601118.SH 的数据\n", + "成功获取 601121.SH 的数据\n", + "成功获取 601126.SH 的数据\n", + "成功获取 601127.SH 的数据\n", + "成功获取 601128.SH 的数据\n", + "成功获取 601133.SH 的数据\n", + "成功获取 601136.SH 的数据\n", + "成功获取 601137.SH 的数据\n", + "成功获取 601138.SH 的数据\n", + "成功获取 601139.SH 的数据\n", + "成功获取 601155.SH 的数据\n", + "成功获取 601156.SH 的数据\n", + "成功获取 601158.SH 的数据\n", + "成功获取 601162.SH 的数据\n", + "成功获取 601163.SH 的数据\n", + "成功获取 601166.SH 的数据\n", + "成功获取 601168.SH 的数据\n", + "成功获取 601169.SH 的数据\n", + "成功获取 601177.SH 的数据\n", + "成功获取 601179.SH 的数据\n", + "成功获取 601186.SH 的数据\n", + "成功获取 601187.SH 的数据\n", + "成功获取 601188.SH 的数据\n", + "成功获取 601198.SH 的数据\n", + "成功获取 601199.SH 的数据\n", + "成功获取 601200.SH 的数据\n", + "成功获取 601208.SH 的数据\n", + "成功获取 601211.SH 的数据\n", + "成功获取 601212.SH 的数据\n", + "成功获取 601216.SH 的数据\n", + "成功获取 601218.SH 的数据\n", + "成功获取 601222.SH 的数据\n", + "成功获取 601225.SH 的数据\n", + "成功获取 601226.SH 的数据\n", + "成功获取 601228.SH 的数据\n", + "成功获取 601229.SH 的数据\n", + "成功获取 601231.SH 的数据\n", + "成功获取 601233.SH 的数据\n", + "成功获取 601236.SH 的数据\n", + "成功获取 601238.SH 的数据\n", + "成功获取 601279.SH 的数据\n", + "成功获取 601288.SH 的数据\n", + "成功获取 601298.SH 的数据\n", + "成功获取 601311.SH 的数据\n", + "成功获取 601318.SH 的数据\n", + "成功获取 601319.SH 的数据\n", + "成功获取 601326.SH 的数据\n", + "成功获取 601328.SH 的数据\n", + "成功获取 601330.SH 的数据\n", + "成功获取 601333.SH 的数据\n", + "成功获取 601336.SH 的数据\n", + "成功获取 601339.SH 的数据\n", + "成功获取 601360.SH 的数据\n", + "成功获取 601366.SH 的数据\n", + "成功获取 601368.SH 的数据\n", + "成功获取 601369.SH 的数据\n", + "成功获取 601375.SH 的数据\n", + "成功获取 601377.SH 的数据\n", + "成功获取 601388.SH 的数据\n", + "成功获取 601390.SH 的数据\n", + "成功获取 601398.SH 的数据\n", + "成功获取 601399.SH 的数据\n", + "成功获取 601456.SH 的数据\n", + "成功获取 601500.SH 的数据\n", + "成功获取 601512.SH 的数据\n", + "成功获取 601515.SH 的数据\n", + "成功获取 601518.SH 的数据\n", + "成功获取 601519.SH 的数据\n", + "成功获取 601528.SH 的数据\n", + "成功获取 601555.SH 的数据\n", + "成功获取 601566.SH 的数据\n", + "成功获取 601567.SH 的数据\n", + "成功获取 601568.SH 的数据\n", + "成功获取 601577.SH 的数据\n", + "成功获取 601579.SH 的数据\n", + "成功获取 601588.SH 的数据\n", + "成功获取 601595.SH 的数据\n", + "成功获取 601598.SH 的数据\n", + "成功获取 601599.SH 的数据\n", + "成功获取 601600.SH 的数据\n", + "成功获取 601601.SH 的数据\n", + "成功获取 601606.SH 的数据\n", + "成功获取 601607.SH 的数据\n", + "成功获取 601608.SH 的数据\n", + "成功获取 601609.SH 的数据\n", + "成功获取 601611.SH 的数据\n", + "成功获取 601615.SH 的数据\n", + "成功获取 601616.SH 的数据\n", + "成功获取 601618.SH 的数据\n", + "成功获取 601619.SH 的数据\n", + "成功获取 601628.SH 的数据\n", + "成功获取 601633.SH 的数据\n", + "成功获取 601636.SH 的数据\n", + "成功获取 601658.SH 的数据\n", + "成功获取 601665.SH 的数据\n", + "成功获取 601666.SH 的数据\n", + "成功获取 601668.SH 的数据\n", + "成功获取 601669.SH 的数据\n", + "成功获取 601677.SH 的数据\n", + "成功获取 601678.SH 的数据\n", + "成功获取 601686.SH 的数据\n", + "成功获取 601688.SH 的数据\n", + "成功获取 601689.SH 的数据\n", + "成功获取 601696.SH 的数据\n", + "成功获取 601698.SH 的数据\n", + "成功获取 601699.SH 的数据\n", + "成功获取 601700.SH 的数据\n", + "成功获取 601702.SH 的数据\n", + "成功获取 601717.SH 的数据\n", + "成功获取 601718.SH 的数据\n", + "成功获取 601727.SH 的数据\n", + "成功获取 601728.SH 的数据\n", + "成功获取 601766.SH 的数据\n", + "成功获取 601777.SH 的数据\n", + "成功获取 601778.SH 的数据\n", + "成功获取 601788.SH 的数据\n", + "成功获取 601789.SH 的数据\n", + "成功获取 601798.SH 的数据\n", + "成功获取 601799.SH 的数据\n", + "成功获取 601800.SH 的数据\n", + "成功获取 601801.SH 的数据\n", + "成功获取 601808.SH 的数据\n", + "成功获取 601811.SH 的数据\n", + "成功获取 601816.SH 的数据\n", + "成功获取 601818.SH 的数据\n", + "成功获取 601825.SH 的数据\n", + "成功获取 601827.SH 的数据\n", + "成功获取 601828.SH 的数据\n", + "成功获取 601838.SH 的数据\n", + "成功获取 601857.SH 的数据\n", + "成功获取 601858.SH 的数据\n", + "成功获取 601860.SH 的数据\n", + "成功获取 601865.SH 的数据\n", + "成功获取 601866.SH 的数据\n", + "成功获取 601868.SH 的数据\n", + "成功获取 601869.SH 的数据\n", + "成功获取 601872.SH 的数据\n", + "成功获取 601877.SH 的数据\n", + "成功获取 601878.SH 的数据\n", + "成功获取 601880.SH 的数据\n", + "成功获取 601881.SH 的数据\n", + "成功获取 601882.SH 的数据\n", + "成功获取 601886.SH 的数据\n", + "成功获取 601888.SH 的数据\n", + "成功获取 601890.SH 的数据\n", + "成功获取 601898.SH 的数据\n", + "成功获取 601899.SH 的数据\n", + "成功获取 601900.SH 的数据\n", + "成功获取 601901.SH 的数据\n", + "成功获取 601908.SH 的数据\n", + "成功获取 601916.SH 的数据\n", + "成功获取 601918.SH 的数据\n", + "成功获取 601919.SH 的数据\n", + "成功获取 601921.SH 的数据\n", + "成功获取 601928.SH 的数据\n", + "成功获取 601929.SH 的数据\n", + "成功获取 601933.SH 的数据\n", + "成功获取 601939.SH 的数据\n", + "成功获取 601949.SH 的数据\n", + "成功获取 601952.SH 的数据\n", + "成功获取 601956.SH 的数据\n", + "成功获取 601958.SH 的数据\n", + "成功获取 601963.SH 的数据\n", + "成功获取 601965.SH 的数据\n", + "成功获取 601966.SH 的数据\n", + "成功获取 601968.SH 的数据\n", + "成功获取 601969.SH 的数据\n", + "成功获取 601975.SH 的数据\n", + "成功获取 601985.SH 的数据\n", + "成功获取 601988.SH 的数据\n", + "成功获取 601989.SH 的数据\n", + "成功获取 601990.SH 的数据\n", + "成功获取 601991.SH 的数据\n", + "成功获取 601992.SH 的数据\n", + "成功获取 601995.SH 的数据\n", + "成功获取 601996.SH 的数据\n", + "成功获取 601997.SH 的数据\n", + "成功获取 601998.SH 的数据\n", + "成功获取 601999.SH 的数据\n", + "成功获取 603000.SH 的数据\n", + "成功获取 603001.SH 的数据\n", + "成功获取 603002.SH 的数据\n", + "成功获取 603003.SH 的数据\n", + "成功获取 603004.SH 的数据\n", + "成功获取 603005.SH 的数据\n", + "成功获取 603006.SH 的数据\n", + "成功获取 603007.SH 的数据\n", + "成功获取 603008.SH 的数据\n", + "成功获取 603009.SH 的数据\n", + "成功获取 603010.SH 的数据\n", + "成功获取 603011.SH 的数据\n", + "成功获取 603012.SH 的数据\n", + "成功获取 603013.SH 的数据\n", + "成功获取 603015.SH 的数据\n", + "成功获取 603016.SH 的数据\n", + "成功获取 603017.SH 的数据\n", + "成功获取 603018.SH 的数据\n", + "成功获取 603019.SH 的数据\n", + "成功获取 603020.SH 的数据\n", + "成功获取 603021.SH 的数据\n", + "成功获取 603022.SH 的数据\n", + "成功获取 603023.SH 的数据\n", + "成功获取 603025.SH 的数据\n", + "成功获取 603026.SH 的数据\n", + "成功获取 603027.SH 的数据\n", + "成功获取 603028.SH 的数据\n", + "成功获取 603029.SH 的数据\n", + "成功获取 603030.SH 的数据\n", + "成功获取 603031.SH 的数据\n", + "成功获取 603032.SH 的数据\n", + "成功获取 603033.SH 的数据\n", + "成功获取 603035.SH 的数据\n", + "成功获取 603036.SH 的数据\n", + "成功获取 603037.SH 的数据\n", + "成功获取 603038.SH 的数据\n", + "成功获取 603039.SH 的数据\n", + "成功获取 603040.SH 的数据\n", + "成功获取 603041.SH 的数据\n", + "成功获取 603042.SH 的数据\n", + "成功获取 603043.SH 的数据\n", + "已调用300次API,等待 0.87 秒以满足速率限制...\n", + "成功获取 603045.SH 的数据\n", + "成功获取 603048.SH 的数据\n", + "成功获取 603050.SH 的数据\n", + "成功获取 603051.SH 的数据\n", + "成功获取 603052.SH 的数据\n", + "成功获取 603053.SH 的数据\n", + "成功获取 603055.SH 的数据\n", + "成功获取 603056.SH 的数据\n", + "成功获取 603057.SH 的数据\n", + "成功获取 603058.SH 的数据\n", + "成功获取 603059.SH 的数据\n", + "成功获取 603060.SH 的数据\n", + "成功获取 603061.SH 的数据\n", + "成功获取 603062.SH 的数据\n", + "成功获取 603063.SH 的数据\n", + "成功获取 603065.SH 的数据\n", + "成功获取 603066.SH 的数据\n", + "成功获取 603067.SH 的数据\n", + "成功获取 603068.SH 的数据\n", + "成功获取 603069.SH 的数据\n", + "成功获取 603070.SH 的数据\n", + "成功获取 603071.SH 的数据\n", + "成功获取 603072.SH 的数据\n", + "成功获取 603073.SH 的数据\n", + "成功获取 603075.SH 的数据\n", + "成功获取 603076.SH 的数据\n", + "成功获取 603077.SH 的数据\n", + "成功获取 603078.SH 的数据\n", + "成功获取 603079.SH 的数据\n", + "成功获取 603080.SH 的数据\n", + "成功获取 603081.SH 的数据\n", + "成功获取 603082.SH 的数据\n", + "成功获取 603083.SH 的数据\n", + "成功获取 603085.SH 的数据\n", + "成功获取 603086.SH 的数据\n", + "成功获取 603087.SH 的数据\n", + "成功获取 603088.SH 的数据\n", + "成功获取 603089.SH 的数据\n", + "成功获取 603090.SH 的数据\n", + "成功获取 603091.SH 的数据\n", + "成功获取 603093.SH 的数据\n", + "成功获取 603095.SH 的数据\n", + "成功获取 603096.SH 的数据\n", + "成功获取 603097.SH 的数据\n", + "成功获取 603098.SH 的数据\n", + "成功获取 603099.SH 的数据\n", + "成功获取 603100.SH 的数据\n", + "成功获取 603101.SH 的数据\n", + "成功获取 603102.SH 的数据\n", + "成功获取 603103.SH 的数据\n", + "成功获取 603105.SH 的数据\n", + "成功获取 603106.SH 的数据\n", + "成功获取 603107.SH 的数据\n", + "成功获取 603108.SH 的数据\n", + "成功获取 603109.SH 的数据\n", + "成功获取 603110.SH 的数据\n", + "成功获取 603111.SH 的数据\n", + "成功获取 603112.SH 的数据\n", + "成功获取 603113.SH 的数据\n", + "成功获取 603115.SH 的数据\n", + "成功获取 603116.SH 的数据\n", + "成功获取 603117.SH 的数据\n", + "成功获取 603118.SH 的数据\n", + "成功获取 603119.SH 的数据\n", + "成功获取 603121.SH 的数据\n", + "成功获取 603122.SH 的数据\n", + "成功获取 603123.SH 的数据\n", + "成功获取 603125.SH 的数据\n", + "成功获取 603126.SH 的数据\n", + "成功获取 603127.SH 的数据\n", + "成功获取 603128.SH 的数据\n", + "成功获取 603129.SH 的数据\n", + "成功获取 603130.SH 的数据\n", + "成功获取 603131.SH 的数据\n", + "成功获取 603132.SH 的数据\n", + "成功获取 603135.SH 的数据\n", + "成功获取 603136.SH 的数据\n", + "成功获取 603137.SH 的数据\n", + "成功获取 603138.SH 的数据\n", + "成功获取 603139.SH 的数据\n", + "成功获取 603150.SH 的数据\n", + "成功获取 603151.SH 的数据\n", + "成功获取 603153.SH 的数据\n", + "成功获取 603155.SH 的数据\n", + "成功获取 603156.SH 的数据\n", + "成功获取 603158.SH 的数据\n", + "成功获取 603159.SH 的数据\n", + "成功获取 603160.SH 的数据\n", + "成功获取 603161.SH 的数据\n", + "成功获取 603162.SH 的数据\n", + "成功获取 603163.SH 的数据\n", + "成功获取 603165.SH 的数据\n", + "成功获取 603166.SH 的数据\n", + "成功获取 603167.SH 的数据\n", + "成功获取 603168.SH 的数据\n", + "成功获取 603169.SH 的数据\n", + "成功获取 603170.SH 的数据\n", + "成功获取 603171.SH 的数据\n", + "成功获取 603172.SH 的数据\n", + "成功获取 603173.SH 的数据\n", + "成功获取 603176.SH 的数据\n", + "成功获取 603177.SH 的数据\n", + "成功获取 603178.SH 的数据\n", + "成功获取 603179.SH 的数据\n", + "成功获取 603180.SH 的数据\n", + "成功获取 603181.SH 的数据\n", + "成功获取 603182.SH 的数据\n", + "成功获取 603183.SH 的数据\n", + "成功获取 603185.SH 的数据\n", + "成功获取 603186.SH 的数据\n", + "成功获取 603187.SH 的数据\n", + "成功获取 603188.SH 的数据\n", + "成功获取 603189.SH 的数据\n", + "成功获取 603190.SH 的数据\n", + "成功获取 603191.SH 的数据\n", + "成功获取 603192.SH 的数据\n", + "成功获取 603193.SH 的数据\n", + "成功获取 603194.SH 的数据\n", + "成功获取 603195.SH 的数据\n", + "成功获取 603196.SH 的数据\n", + "成功获取 603197.SH 的数据\n", + "成功获取 603198.SH 的数据\n", + "成功获取 603199.SH 的数据\n", + "成功获取 603200.SH 的数据\n", + "成功获取 603201.SH 的数据\n", + "成功获取 603203.SH 的数据\n", + "成功获取 603205.SH 的数据\n", + "成功获取 603206.SH 的数据\n", + "成功获取 603207.SH 的数据\n", + "成功获取 603208.SH 的数据\n", + "成功获取 603209.SH 的数据\n", + "成功获取 603211.SH 的数据\n", + "成功获取 603212.SH 的数据\n", + "成功获取 603213.SH 的数据\n", + "成功获取 603214.SH 的数据\n", + "成功获取 603215.SH 的数据\n", + "成功获取 603216.SH 的数据\n", + "成功获取 603217.SH 的数据\n", + "成功获取 603218.SH 的数据\n", + "成功获取 603219.SH 的数据\n", + "成功获取 603220.SH 的数据\n", + "成功获取 603221.SH 的数据\n", + "成功获取 603222.SH 的数据\n", + "成功获取 603223.SH 的数据\n", + "成功获取 603225.SH 的数据\n", + "成功获取 603226.SH 的数据\n", + "成功获取 603227.SH 的数据\n", + "成功获取 603228.SH 的数据\n", + "成功获取 603229.SH 的数据\n", + "成功获取 603230.SH 的数据\n", + "成功获取 603231.SH 的数据\n", + "成功获取 603232.SH 的数据\n", + "成功获取 603233.SH 的数据\n", + "成功获取 603235.SH 的数据\n", + "成功获取 603236.SH 的数据\n", + "成功获取 603237.SH 的数据\n", + "成功获取 603238.SH 的数据\n", + "成功获取 603239.SH 的数据\n", + "成功获取 603255.SH 的数据\n", + "成功获取 603256.SH 的数据\n", + "成功获取 603258.SH 的数据\n", + "成功获取 603259.SH 的数据\n", + "成功获取 603260.SH 的数据\n", + "成功获取 603261.SH 的数据\n", + "成功获取 603266.SH 的数据\n", + "成功获取 603267.SH 的数据\n", + "成功获取 603268.SH 的数据\n", + "成功获取 603269.SH 的数据\n", + "成功获取 603270.SH 的数据\n", + "成功获取 603272.SH 的数据\n", + "成功获取 603273.SH 的数据\n", + "成功获取 603275.SH 的数据\n", + "成功获取 603276.SH 的数据\n", + "成功获取 603277.SH 的数据\n", + "成功获取 603278.SH 的数据\n", + "成功获取 603279.SH 的数据\n", + "成功获取 603280.SH 的数据\n", + "成功获取 603281.SH 的数据\n", + "成功获取 603282.SH 的数据\n", + "成功获取 603283.SH 的数据\n", + "成功获取 603285.SH 的数据\n", + "成功获取 603286.SH 的数据\n", + "成功获取 603288.SH 的数据\n", + "成功获取 603289.SH 的数据\n", + "成功获取 603290.SH 的数据\n", + "成功获取 603291.SH 的数据\n", + "成功获取 603296.SH 的数据\n", + "成功获取 603297.SH 的数据\n", + "成功获取 603298.SH 的数据\n", + "成功获取 603299.SH 的数据\n", + "成功获取 603300.SH 的数据\n", + "成功获取 603301.SH 的数据\n", + "成功获取 603303.SH 的数据\n", + "成功获取 603305.SH 的数据\n", + "成功获取 603306.SH 的数据\n", + "成功获取 603307.SH 的数据\n", + "成功获取 603308.SH 的数据\n", + "成功获取 603309.SH 的数据\n", + "成功获取 603310.SH 的数据\n", + "成功获取 603311.SH 的数据\n", + "成功获取 603312.SH 的数据\n", + "成功获取 603313.SH 的数据\n", + "成功获取 603315.SH 的数据\n", + "成功获取 603316.SH 的数据\n", + "成功获取 603317.SH 的数据\n", + "成功获取 603318.SH 的数据\n", + "成功获取 603319.SH 的数据\n", + "成功获取 603320.SH 的数据\n", + "成功获取 603321.SH 的数据\n", + "成功获取 603322.SH 的数据\n", + "成功获取 603323.SH 的数据\n", + "成功获取 603324.SH 的数据\n", + "成功获取 603325.SH 的数据\n", + "成功获取 603326.SH 的数据\n", + "成功获取 603327.SH 的数据\n", + "成功获取 603328.SH 的数据\n", + "成功获取 603329.SH 的数据\n", + "成功获取 603330.SH 的数据\n", + "成功获取 603331.SH 的数据\n", + "成功获取 603332.SH 的数据\n", + "成功获取 603333.SH 的数据\n", + "成功获取 603335.SH 的数据\n", + "成功获取 603336.SH 的数据\n", + "成功获取 603337.SH 的数据\n", + "成功获取 603338.SH 的数据\n", + "成功获取 603339.SH 的数据\n", + "成功获取 603341.SH 的数据\n", + "成功获取 603344.SH 的数据\n", + "成功获取 603345.SH 的数据\n", + "成功获取 603348.SH 的数据\n", + "成功获取 603350.SH 的数据\n", + "成功获取 603351.SH 的数据\n", + "成功获取 603353.SH 的数据\n", + "成功获取 603355.SH 的数据\n", + "成功获取 603356.SH 的数据\n", + "成功获取 603357.SH 的数据\n", + "成功获取 603358.SH 的数据\n", + "成功获取 603359.SH 的数据\n", + "成功获取 603360.SH 的数据\n", + "成功获取 603363.SH 的数据\n", + "成功获取 603365.SH 的数据\n", + "成功获取 603366.SH 的数据\n", + "成功获取 603367.SH 的数据\n", + "成功获取 603368.SH 的数据\n", + "成功获取 603369.SH 的数据\n", + "成功获取 603373.SH 的数据\n", + "成功获取 603375.SH 的数据\n", + "成功获取 603377.SH 的数据\n", + "成功获取 603378.SH 的数据\n", + "成功获取 603379.SH 的数据\n", + "成功获取 603380.SH 的数据\n", + "成功获取 603381.SH 的数据\n", + "成功获取 603383.SH 的数据\n", + "成功获取 603385.SH 的数据\n", + "成功获取 603386.SH 的数据\n", + "成功获取 603387.SH 的数据\n", + "成功获取 603388.SH 的数据\n", + "成功获取 603389.SH 的数据\n", + "成功获取 603390.SH 的数据\n", + "成功获取 603391.SH 的数据\n", + "成功获取 603392.SH 的数据\n", + "成功获取 603393.SH 的数据\n", + "成功获取 603395.SH 的数据\n", + "成功获取 603396.SH 的数据\n", + "成功获取 603398.SH 的数据\n", + "成功获取 603399.SH 的数据\n", + "成功获取 603408.SH 的数据\n", + "成功获取 603416.SH 的数据\n", + "成功获取 603421.SH 的数据\n", + "成功获取 603429.SH 的数据\n", + "成功获取 603439.SH 的数据\n", + "成功获取 603444.SH 的数据\n", + "成功获取 603456.SH 的数据\n", + "成功获取 603458.SH 的数据\n", + "成功获取 603466.SH 的数据\n", + "成功获取 603477.SH 的数据\n", + "成功获取 603486.SH 的数据\n", + "成功获取 603488.SH 的数据\n", + "成功获取 603489.SH 的数据\n", + "成功获取 603496.SH 的数据\n", + "成功获取 603499.SH 的数据\n", + "成功获取 603500.SH 的数据\n", + "成功获取 603501.SH 的数据\n", + "成功获取 603505.SH 的数据\n", + "成功获取 603506.SH 的数据\n", + "成功获取 603507.SH 的数据\n", + "成功获取 603508.SH 的数据\n", + "成功获取 603511.SH 的数据\n", + "成功获取 603515.SH 的数据\n", + "成功获取 603516.SH 的数据\n", + "成功获取 603517.SH 的数据\n", + "成功获取 603518.SH 的数据\n", + "成功获取 603519.SH 的数据\n", + "成功获取 603520.SH 的数据\n", + "成功获取 603527.SH 的数据\n", + "成功获取 603528.SH 的数据\n", + "成功获取 603529.SH 的数据\n", + "成功获取 603530.SH 的数据\n", + "成功获取 603533.SH 的数据\n", + "成功获取 603535.SH 的数据\n", + "已调用300次API,等待 8.80 秒以满足速率限制...\n", + "成功获取 603536.SH 的数据\n", + "成功获取 603538.SH 的数据\n", + "成功获取 603551.SH 的数据\n", + "成功获取 603556.SH 的数据\n", + "成功获取 603557.SH 的数据\n", + "成功获取 603558.SH 的数据\n", + "成功获取 603559.SH 的数据\n", + "成功获取 603565.SH 的数据\n", + "成功获取 603566.SH 的数据\n", + "成功获取 603567.SH 的数据\n", + "成功获取 603568.SH 的数据\n", + "成功获取 603569.SH 的数据\n", + "成功获取 603577.SH 的数据\n", + "成功获取 603578.SH 的数据\n", + "成功获取 603579.SH 的数据\n", + "成功获取 603580.SH 的数据\n", + "成功获取 603583.SH 的数据\n", + "成功获取 603585.SH 的数据\n", + "成功获取 603586.SH 的数据\n", + "成功获取 603587.SH 的数据\n", + "成功获取 603588.SH 的数据\n", + "成功获取 603589.SH 的数据\n", + "成功获取 603590.SH 的数据\n", + "成功获取 603595.SH 的数据\n", + "成功获取 603596.SH 的数据\n", + "成功获取 603598.SH 的数据\n", + "成功获取 603599.SH 的数据\n", + "成功获取 603600.SH 的数据\n", + "成功获取 603601.SH 的数据\n", + "成功获取 603602.SH 的数据\n", + "成功获取 603605.SH 的数据\n", + "成功获取 603606.SH 的数据\n", + "成功获取 603607.SH 的数据\n", + "成功获取 603608.SH 的数据\n", + "成功获取 603609.SH 的数据\n", + "成功获取 603610.SH 的数据\n", + "成功获取 603611.SH 的数据\n", + "成功获取 603612.SH 的数据\n", + "成功获取 603613.SH 的数据\n", + "成功获取 603615.SH 的数据\n", + "成功获取 603616.SH 的数据\n", + "成功获取 603617.SH 的数据\n", + "成功获取 603618.SH 的数据\n", + "成功获取 603619.SH 的数据\n", + "成功获取 603626.SH 的数据\n", + "成功获取 603628.SH 的数据\n", + "成功获取 603629.SH 的数据\n", + "成功获取 603630.SH 的数据\n", + "成功获取 603633.SH 的数据\n", + "成功获取 603636.SH 的数据\n", + "成功获取 603637.SH 的数据\n", + "成功获取 603638.SH 的数据\n", + "成功获取 603639.SH 的数据\n", + "成功获取 603648.SH 的数据\n", + "成功获取 603650.SH 的数据\n", + "成功获取 603655.SH 的数据\n", + "成功获取 603656.SH 的数据\n", + "成功获取 603657.SH 的数据\n", + "成功获取 603658.SH 的数据\n", + "成功获取 603659.SH 的数据\n", + "成功获取 603660.SH 的数据\n", + "成功获取 603661.SH 的数据\n", + "成功获取 603662.SH 的数据\n", + "成功获取 603663.SH 的数据\n", + "成功获取 603665.SH 的数据\n", + "成功获取 603666.SH 的数据\n", + "成功获取 603667.SH 的数据\n", + "成功获取 603668.SH 的数据\n", + "成功获取 603669.SH 的数据\n", + "成功获取 603676.SH 的数据\n", + "成功获取 603677.SH 的数据\n", + "成功获取 603678.SH 的数据\n", + "成功获取 603679.SH 的数据\n", + "成功获取 603680.SH 的数据\n", + "成功获取 603681.SH 的数据\n", + "成功获取 603682.SH 的数据\n", + "成功获取 603683.SH 的数据\n", + "成功获取 603685.SH 的数据\n", + "成功获取 603686.SH 的数据\n", + "成功获取 603687.SH 的数据\n", + "成功获取 603688.SH 的数据\n", + "成功获取 603689.SH 的数据\n", + "成功获取 603690.SH 的数据\n", + "成功获取 603693.SH 的数据\n", + "成功获取 603696.SH 的数据\n", + "成功获取 603697.SH 的数据\n", + "成功获取 603698.SH 的数据\n", + "成功获取 603699.SH 的数据\n", + "成功获取 603700.SH 的数据\n", + "成功获取 603701.SH 的数据\n", + "成功获取 603703.SH 的数据\n", + "成功获取 603706.SH 的数据\n", + "成功获取 603707.SH 的数据\n", + "成功获取 603708.SH 的数据\n", + "成功获取 603709.SH 的数据\n", + "成功获取 603711.SH 的数据\n", + "成功获取 603712.SH 的数据\n", + "成功获取 603713.SH 的数据\n", + "成功获取 603716.SH 的数据\n", + "成功获取 603717.SH 的数据\n", + "成功获取 603718.SH 的数据\n", + "成功获取 603719.SH 的数据\n", + "成功获取 603721.SH 的数据\n", + "成功获取 603722.SH 的数据\n", + "成功获取 603725.SH 的数据\n", + "成功获取 603726.SH 的数据\n", + "成功获取 603727.SH 的数据\n", + "成功获取 603728.SH 的数据\n", + "成功获取 603729.SH 的数据\n", + "成功获取 603730.SH 的数据\n", + "成功获取 603733.SH 的数据\n", + "成功获取 603737.SH 的数据\n", + "成功获取 603738.SH 的数据\n", + "成功获取 603739.SH 的数据\n", + "成功获取 603755.SH 的数据\n", + "成功获取 603757.SH 的数据\n", + "成功获取 603758.SH 的数据\n", + "成功获取 603759.SH 的数据\n", + "成功获取 603766.SH 的数据\n", + "成功获取 603767.SH 的数据\n", + "成功获取 603768.SH 的数据\n", + "成功获取 603773.SH 的数据\n", + "成功获取 603776.SH 的数据\n", + "成功获取 603777.SH 的数据\n", + "成功获取 603778.SH 的数据\n", + "成功获取 603779.SH 的数据\n", + "成功获取 603786.SH 的数据\n", + "成功获取 603787.SH 的数据\n", + "成功获取 603788.SH 的数据\n", + "成功获取 603789.SH 的数据\n", + "成功获取 603790.SH 的数据\n", + "成功获取 603797.SH 的数据\n", + "成功获取 603798.SH 的数据\n", + "成功获取 603799.SH 的数据\n", + "成功获取 603800.SH 的数据\n", + "成功获取 603801.SH 的数据\n", + "成功获取 603803.SH 的数据\n", + "成功获取 603806.SH 的数据\n", + "成功获取 603808.SH 的数据\n", + "成功获取 603809.SH 的数据\n", + "成功获取 603810.SH 的数据\n", + "成功获取 603811.SH 的数据\n", + "成功获取 603813.SH 的数据\n", + "成功获取 603815.SH 的数据\n", + "成功获取 603816.SH 的数据\n", + "成功获取 603817.SH 的数据\n", + "成功获取 603818.SH 的数据\n", + "成功获取 603819.SH 的数据\n", + "成功获取 603822.SH 的数据\n", + "成功获取 603823.SH 的数据\n", + "成功获取 603825.SH 的数据\n", + "成功获取 603826.SH 的数据\n", + "成功获取 603828.SH 的数据\n", + "成功获取 603829.SH 的数据\n", + "成功获取 603833.SH 的数据\n", + "成功获取 603836.SH 的数据\n", + "成功获取 603838.SH 的数据\n", + "成功获取 603839.SH 的数据\n", + "成功获取 603843.SH 的数据\n", + "成功获取 603848.SH 的数据\n", + "成功获取 603855.SH 的数据\n", + "成功获取 603856.SH 的数据\n", + "成功获取 603858.SH 的数据\n", + "成功获取 603859.SH 的数据\n", + "成功获取 603860.SH 的数据\n", + "成功获取 603861.SH 的数据\n", + "成功获取 603863.SH 的数据\n", + "成功获取 603866.SH 的数据\n", + "成功获取 603867.SH 的数据\n", + "成功获取 603868.SH 的数据\n", + "成功获取 603869.SH 的数据\n", + "成功获取 603871.SH 的数据\n", + "成功获取 603876.SH 的数据\n", + "成功获取 603877.SH 的数据\n", + "成功获取 603878.SH 的数据\n", + "成功获取 603879.SH 的数据\n", + "成功获取 603880.SH 的数据\n", + "成功获取 603881.SH 的数据\n", + "成功获取 603882.SH 的数据\n", + "成功获取 603883.SH 的数据\n", + "成功获取 603885.SH 的数据\n", + "成功获取 603886.SH 的数据\n", + "成功获取 603887.SH 的数据\n", + "成功获取 603888.SH 的数据\n", + "成功获取 603889.SH 的数据\n", + "成功获取 603890.SH 的数据\n", + "成功获取 603893.SH 的数据\n", + "成功获取 603895.SH 的数据\n", + "成功获取 603896.SH 的数据\n", + "成功获取 603897.SH 的数据\n", + "成功获取 603898.SH 的数据\n", + "成功获取 603899.SH 的数据\n", + "成功获取 603900.SH 的数据\n", + "成功获取 603901.SH 的数据\n", + "成功获取 603903.SH 的数据\n", + "成功获取 603906.SH 的数据\n", + "成功获取 603908.SH 的数据\n", + "成功获取 603909.SH 的数据\n", + "成功获取 603912.SH 的数据\n", + "成功获取 603915.SH 的数据\n", + "成功获取 603916.SH 的数据\n", + "成功获取 603917.SH 的数据\n", + "成功获取 603918.SH 的数据\n", + "成功获取 603919.SH 的数据\n", + "成功获取 603920.SH 的数据\n", + "成功获取 603922.SH 的数据\n", + "成功获取 603926.SH 的数据\n", + "成功获取 603927.SH 的数据\n", + "成功获取 603928.SH 的数据\n", + "成功获取 603929.SH 的数据\n", + "成功获取 603931.SH 的数据\n", + "成功获取 603933.SH 的数据\n", + "成功获取 603936.SH 的数据\n", + "成功获取 603937.SH 的数据\n", + "成功获取 603938.SH 的数据\n", + "成功获取 603939.SH 的数据\n", + "成功获取 603948.SH 的数据\n", + "成功获取 603949.SH 的数据\n", + "成功获取 603950.SH 的数据\n", + "成功获取 603955.SH 的数据\n", + "成功获取 603956.SH 的数据\n", + "成功获取 603958.SH 的数据\n", + "成功获取 603959.SH 的数据\n", + "成功获取 603960.SH 的数据\n", + "成功获取 603963.SH 的数据\n", + "成功获取 603966.SH 的数据\n", + "成功获取 603967.SH 的数据\n", + "成功获取 603968.SH 的数据\n", + "成功获取 603969.SH 的数据\n", + "成功获取 603970.SH 的数据\n", + "成功获取 603976.SH 的数据\n", + "成功获取 603977.SH 的数据\n", + "成功获取 603978.SH 的数据\n", + "成功获取 603979.SH 的数据\n", + "成功获取 603980.SH 的数据\n", + "成功获取 603982.SH 的数据\n", + "成功获取 603983.SH 的数据\n", + "成功获取 603985.SH 的数据\n", + "成功获取 603986.SH 的数据\n", + "成功获取 603987.SH 的数据\n", + "成功获取 603988.SH 的数据\n", + "成功获取 603989.SH 的数据\n", + "成功获取 603990.SH 的数据\n", + "成功获取 603991.SH 的数据\n", + "成功获取 603992.SH 的数据\n", + "成功获取 603993.SH 的数据\n", + "成功获取 603995.SH 的数据\n", + "成功获取 603997.SH 的数据\n", + "成功获取 603998.SH 的数据\n", + "成功获取 603999.SH 的数据\n", + "成功获取 605001.SH 的数据\n", + "成功获取 605003.SH 的数据\n", + "成功获取 605005.SH 的数据\n", + "成功获取 605006.SH 的数据\n", + "成功获取 605007.SH 的数据\n", + "成功获取 605008.SH 的数据\n", + "成功获取 605009.SH 的数据\n", + "成功获取 605011.SH 的数据\n", + "成功获取 605016.SH 的数据\n", + "成功获取 605018.SH 的数据\n", + "成功获取 605020.SH 的数据\n", + "成功获取 605028.SH 的数据\n", + "成功获取 605033.SH 的数据\n", + "成功获取 605050.SH 的数据\n", + "成功获取 605055.SH 的数据\n", + "成功获取 605056.SH 的数据\n", + "成功获取 605058.SH 的数据\n", + "成功获取 605060.SH 的数据\n", + "成功获取 605066.SH 的数据\n", + "成功获取 605068.SH 的数据\n", + "成功获取 605069.SH 的数据\n", + "成功获取 605077.SH 的数据\n", + "成功获取 605080.SH 的数据\n", + "成功获取 605081.SH 的数据\n", + "成功获取 605086.SH 的数据\n", + "成功获取 605088.SH 的数据\n", + "成功获取 605089.SH 的数据\n", + "成功获取 605090.SH 的数据\n", + "成功获取 605098.SH 的数据\n", + "成功获取 605099.SH 的数据\n", + "成功获取 605100.SH 的数据\n", + "成功获取 605108.SH 的数据\n", + "成功获取 605111.SH 的数据\n", + "成功获取 605116.SH 的数据\n", + "成功获取 605117.SH 的数据\n", + "成功获取 605118.SH 的数据\n", + "成功获取 605122.SH 的数据\n", + "成功获取 605123.SH 的数据\n", + "成功获取 605128.SH 的数据\n", + "成功获取 605133.SH 的数据\n", + "成功获取 605136.SH 的数据\n", + "成功获取 605138.SH 的数据\n", + "成功获取 605151.SH 的数据\n", + "成功获取 605155.SH 的数据\n", + "成功获取 605158.SH 的数据\n", + "成功获取 605162.SH 的数据\n", + "成功获取 605166.SH 的数据\n", + "成功获取 605167.SH 的数据\n", + "成功获取 605168.SH 的数据\n", + "成功获取 605169.SH 的数据\n", + "已调用300次API,等待 7.92 秒以满足速率限制...\n", + "成功获取 605177.SH 的数据\n", + "成功获取 605178.SH 的数据\n", + "成功获取 605179.SH 的数据\n", + "成功获取 605180.SH 的数据\n", + "成功获取 605183.SH 的数据\n", + "成功获取 605186.SH 的数据\n", + "成功获取 605188.SH 的数据\n", + "成功获取 605189.SH 的数据\n", + "成功获取 605196.SH 的数据\n", + "成功获取 605198.SH 的数据\n", + "成功获取 605199.SH 的数据\n", + "成功获取 605208.SH 的数据\n", + "成功获取 605218.SH 的数据\n", + "成功获取 605222.SH 的数据\n", + "成功获取 605228.SH 的数据\n", + "成功获取 605255.SH 的数据\n", + "成功获取 605258.SH 的数据\n", + "成功获取 605259.SH 的数据\n", + "成功获取 605266.SH 的数据\n", + "成功获取 605268.SH 的数据\n", + "成功获取 605277.SH 的数据\n", + "成功获取 605286.SH 的数据\n", + "成功获取 605287.SH 的数据\n", + "成功获取 605288.SH 的数据\n", + "成功获取 605289.SH 的数据\n", + "成功获取 605296.SH 的数据\n", + "成功获取 605298.SH 的数据\n", + "成功获取 605299.SH 的数据\n", + "成功获取 605300.SH 的数据\n", + "成功获取 605303.SH 的数据\n", + "成功获取 605305.SH 的数据\n", + "成功获取 605318.SH 的数据\n", + "成功获取 605319.SH 的数据\n", + "成功获取 605333.SH 的数据\n", + "成功获取 605336.SH 的数据\n", + "成功获取 605337.SH 的数据\n", + "成功获取 605338.SH 的数据\n", + "成功获取 605339.SH 的数据\n", + "成功获取 605358.SH 的数据\n", + "成功获取 605365.SH 的数据\n", + "成功获取 605366.SH 的数据\n", + "成功获取 605368.SH 的数据\n", + "成功获取 605369.SH 的数据\n", + "成功获取 605376.SH 的数据\n", + "成功获取 605377.SH 的数据\n", + "成功获取 605378.SH 的数据\n", + "成功获取 605388.SH 的数据\n", + "成功获取 605389.SH 的数据\n", + "成功获取 605398.SH 的数据\n", + "成功获取 605399.SH 的数据\n", + "成功获取 605488.SH 的数据\n", + "成功获取 605499.SH 的数据\n", + "成功获取 605500.SH 的数据\n", + "成功获取 605507.SH 的数据\n", + "成功获取 605555.SH 的数据\n", + "成功获取 605566.SH 的数据\n", + "成功获取 605567.SH 的数据\n", + "成功获取 605577.SH 的数据\n", + "成功获取 605580.SH 的数据\n", + "成功获取 605588.SH 的数据\n", + "成功获取 605589.SH 的数据\n", + "成功获取 605598.SH 的数据\n", + "成功获取 605599.SH 的数据\n", + "成功获取 688001.SH 的数据\n", + "成功获取 688002.SH 的数据\n", + "成功获取 688003.SH 的数据\n", + "成功获取 688004.SH 的数据\n", + "成功获取 688005.SH 的数据\n", + "成功获取 688006.SH 的数据\n", + "成功获取 688007.SH 的数据\n", + "成功获取 688008.SH 的数据\n", + "成功获取 688009.SH 的数据\n", + "成功获取 688010.SH 的数据\n", + "成功获取 688011.SH 的数据\n", + "成功获取 688012.SH 的数据\n", + "成功获取 688013.SH 的数据\n", + "成功获取 688015.SH 的数据\n", + "成功获取 688016.SH 的数据\n", + "成功获取 688017.SH 的数据\n", + "成功获取 688018.SH 的数据\n", + "成功获取 688019.SH 的数据\n", + "成功获取 688020.SH 的数据\n", + "成功获取 688021.SH 的数据\n", + "成功获取 688022.SH 的数据\n", + "成功获取 688023.SH 的数据\n", + "成功获取 688025.SH 的数据\n", + "成功获取 688026.SH 的数据\n", + "成功获取 688027.SH 的数据\n", + "成功获取 688028.SH 的数据\n", + "成功获取 688029.SH 的数据\n", + "成功获取 688030.SH 的数据\n", + "成功获取 688031.SH 的数据\n", + "成功获取 688032.SH 的数据\n", + "成功获取 688033.SH 的数据\n", + "成功获取 688035.SH 的数据\n", + "成功获取 688036.SH 的数据\n", + "成功获取 688037.SH 的数据\n", + "成功获取 688038.SH 的数据\n", + "成功获取 688039.SH 的数据\n", + "成功获取 688041.SH 的数据\n", + "成功获取 688045.SH 的数据\n", + "成功获取 688046.SH 的数据\n", + "成功获取 688047.SH 的数据\n", + "成功获取 688048.SH 的数据\n", + "成功获取 688049.SH 的数据\n", + "成功获取 688050.SH 的数据\n", + "成功获取 688051.SH 的数据\n", + "成功获取 688052.SH 的数据\n", + "成功获取 688053.SH 的数据\n", + "成功获取 688055.SH 的数据\n", + "成功获取 688056.SH 的数据\n", + "成功获取 688057.SH 的数据\n", + "成功获取 688058.SH 的数据\n", + "成功获取 688059.SH 的数据\n", + "成功获取 688060.SH 的数据\n", + "成功获取 688061.SH 的数据\n", + "成功获取 688062.SH 的数据\n", + "成功获取 688063.SH 的数据\n", + "成功获取 688065.SH 的数据\n", + "成功获取 688066.SH 的数据\n", + "成功获取 688067.SH 的数据\n", + "成功获取 688068.SH 的数据\n", + "成功获取 688069.SH 的数据\n", + "成功获取 688070.SH 的数据\n", + "成功获取 688071.SH 的数据\n", + "成功获取 688072.SH 的数据\n", + "成功获取 688073.SH 的数据\n", + "成功获取 688075.SH 的数据\n", + "成功获取 688076.SH 的数据\n", + "成功获取 688077.SH 的数据\n", + "成功获取 688078.SH 的数据\n", + "成功获取 688079.SH 的数据\n", + "成功获取 688080.SH 的数据\n", + "成功获取 688081.SH 的数据\n", + "成功获取 688082.SH 的数据\n", + "成功获取 688083.SH 的数据\n", + "成功获取 688084.SH 的数据\n", + "成功获取 688085.SH 的数据\n", + "成功获取 688087.SH 的数据\n", + "成功获取 688088.SH 的数据\n", + "成功获取 688089.SH 的数据\n", + "成功获取 688090.SH 的数据\n", + "成功获取 688091.SH 的数据\n", + "成功获取 688092.SH 的数据\n", + "成功获取 688093.SH 的数据\n", + "成功获取 688095.SH 的数据\n", + "成功获取 688096.SH 的数据\n", + "成功获取 688097.SH 的数据\n", + "成功获取 688098.SH 的数据\n", + "成功获取 688099.SH 的数据\n", + "成功获取 688100.SH 的数据\n", + "成功获取 688101.SH 的数据\n", + "成功获取 688102.SH 的数据\n", + "成功获取 688103.SH 的数据\n", + "成功获取 688105.SH 的数据\n", + "成功获取 688106.SH 的数据\n", + "成功获取 688107.SH 的数据\n", + "成功获取 688108.SH 的数据\n", + "成功获取 688109.SH 的数据\n", + "成功获取 688110.SH 的数据\n", + "成功获取 688111.SH 的数据\n", + "成功获取 688112.SH 的数据\n", + "成功获取 688113.SH 的数据\n", + "成功获取 688114.SH 的数据\n", + "成功获取 688115.SH 的数据\n", + "成功获取 688116.SH 的数据\n", + "成功获取 688117.SH 的数据\n", + "成功获取 688118.SH 的数据\n", + "成功获取 688119.SH 的数据\n", + "成功获取 688120.SH 的数据\n", + "成功获取 688121.SH 的数据\n", + "成功获取 688122.SH 的数据\n", + "成功获取 688123.SH 的数据\n", + "成功获取 688125.SH 的数据\n", + "成功获取 688126.SH 的数据\n", + "成功获取 688127.SH 的数据\n", + "成功获取 688128.SH 的数据\n", + "成功获取 688129.SH 的数据\n", + "成功获取 688130.SH 的数据\n", + "成功获取 688131.SH 的数据\n", + "成功获取 688132.SH 的数据\n", + "成功获取 688133.SH 的数据\n", + "成功获取 688135.SH 的数据\n", + "成功获取 688136.SH 的数据\n", + "成功获取 688137.SH 的数据\n", + "成功获取 688138.SH 的数据\n", + "成功获取 688139.SH 的数据\n", + "成功获取 688141.SH 的数据\n", + "成功获取 688143.SH 的数据\n", + "成功获取 688146.SH 的数据\n", + "成功获取 688147.SH 的数据\n", + "成功获取 688148.SH 的数据\n", + "成功获取 688150.SH 的数据\n", + "成功获取 688151.SH 的数据\n", + "成功获取 688152.SH 的数据\n", + "成功获取 688153.SH 的数据\n", + "成功获取 688155.SH 的数据\n", + "成功获取 688156.SH 的数据\n", + "成功获取 688157.SH 的数据\n", + "成功获取 688158.SH 的数据\n", + "成功获取 688159.SH 的数据\n", + "成功获取 688160.SH 的数据\n", + "成功获取 688161.SH 的数据\n", + "成功获取 688162.SH 的数据\n", + "成功获取 688163.SH 的数据\n", + "成功获取 688165.SH 的数据\n", + "成功获取 688166.SH 的数据\n", + "成功获取 688167.SH 的数据\n", + "成功获取 688168.SH 的数据\n", + "成功获取 688169.SH 的数据\n", + "成功获取 688170.SH 的数据\n", + "成功获取 688171.SH 的数据\n", + "成功获取 688172.SH 的数据\n", + "成功获取 688173.SH 的数据\n", + "成功获取 688175.SH 的数据\n", + "成功获取 688176.SH 的数据\n", + "成功获取 688177.SH 的数据\n", + "成功获取 688178.SH 的数据\n", + "成功获取 688179.SH 的数据\n", + "成功获取 688180.SH 的数据\n", + "成功获取 688181.SH 的数据\n", + "成功获取 688182.SH 的数据\n", + "成功获取 688183.SH 的数据\n", + "成功获取 688184.SH 的数据\n", + "成功获取 688185.SH 的数据\n", + "成功获取 688186.SH 的数据\n", + "成功获取 688187.SH 的数据\n", + "成功获取 688188.SH 的数据\n", + "成功获取 688189.SH 的数据\n", + "成功获取 688190.SH 的数据\n", + "成功获取 688191.SH 的数据\n", + "成功获取 688192.SH 的数据\n", + "成功获取 688193.SH 的数据\n", + "成功获取 688195.SH 的数据\n", + "成功获取 688196.SH 的数据\n", + "成功获取 688197.SH 的数据\n", + "成功获取 688198.SH 的数据\n", + "成功获取 688199.SH 的数据\n", + "成功获取 688200.SH 的数据\n", + "成功获取 688201.SH 的数据\n", + "成功获取 688202.SH 的数据\n", + "成功获取 688203.SH 的数据\n", + "成功获取 688205.SH 的数据\n", + "成功获取 688206.SH 的数据\n", + "成功获取 688207.SH 的数据\n", + "成功获取 688208.SH 的数据\n", + "成功获取 688209.SH 的数据\n", + "成功获取 688210.SH 的数据\n", + "成功获取 688211.SH 的数据\n", + "成功获取 688212.SH 的数据\n", + "成功获取 688213.SH 的数据\n", + "成功获取 688215.SH 的数据\n", + "成功获取 688216.SH 的数据\n", + "成功获取 688217.SH 的数据\n", + "成功获取 688218.SH 的数据\n", + "成功获取 688219.SH 的数据\n", + "成功获取 688220.SH 的数据\n", + "成功获取 688221.SH 的数据\n", + "成功获取 688222.SH 的数据\n", + "成功获取 688223.SH 的数据\n", + "成功获取 688225.SH 的数据\n", + "成功获取 688226.SH 的数据\n", + "成功获取 688227.SH 的数据\n", + "成功获取 688228.SH 的数据\n", + "成功获取 688229.SH 的数据\n", + "成功获取 688230.SH 的数据\n", + "成功获取 688231.SH 的数据\n", + "成功获取 688232.SH 的数据\n", + "成功获取 688233.SH 的数据\n", + "成功获取 688234.SH 的数据\n", + "成功获取 688235.SH 的数据\n", + "成功获取 688236.SH 的数据\n", + "成功获取 688237.SH 的数据\n", + "成功获取 688238.SH 的数据\n", + "成功获取 688239.SH 的数据\n", + "成功获取 688244.SH 的数据\n", + "成功获取 688246.SH 的数据\n", + "成功获取 688247.SH 的数据\n", + "成功获取 688248.SH 的数据\n", + "成功获取 688249.SH 的数据\n", + "成功获取 688251.SH 的数据\n", + "成功获取 688252.SH 的数据\n", + "成功获取 688253.SH 的数据\n", + "成功获取 688255.SH 的数据\n", + "成功获取 688256.SH 的数据\n", + "成功获取 688257.SH 的数据\n", + "成功获取 688258.SH 的数据\n", + "成功获取 688259.SH 的数据\n", + "成功获取 688260.SH 的数据\n", + "成功获取 688261.SH 的数据\n", + "成功获取 688262.SH 的数据\n", + "成功获取 688265.SH 的数据\n", + "成功获取 688266.SH 的数据\n", + "成功获取 688267.SH 的数据\n", + "成功获取 688268.SH 的数据\n", + "成功获取 688269.SH 的数据\n", + "成功获取 688270.SH 的数据\n", + "成功获取 688271.SH 的数据\n", + "成功获取 688272.SH 的数据\n", + "成功获取 688273.SH 的数据\n", + "已调用300次API,等待 11.83 秒以满足速率限制...\n", + "成功获取 688275.SH 的数据\n", + "成功获取 688276.SH 的数据\n", + "成功获取 688277.SH 的数据\n", + "成功获取 688278.SH 的数据\n", + "成功获取 688279.SH 的数据\n", + "成功获取 688280.SH 的数据\n", + "成功获取 688281.SH 的数据\n", + "成功获取 688282.SH 的数据\n", + "成功获取 688283.SH 的数据\n", + "成功获取 688285.SH 的数据\n", + "成功获取 688286.SH 的数据\n", + "成功获取 688287.SH 的数据\n", + "成功获取 688288.SH 的数据\n", + "成功获取 688289.SH 的数据\n", + "成功获取 688290.SH 的数据\n", + "成功获取 688291.SH 的数据\n", + "成功获取 688292.SH 的数据\n", + "成功获取 688293.SH 的数据\n", + "成功获取 688295.SH 的数据\n", + "成功获取 688296.SH 的数据\n", + "成功获取 688297.SH 的数据\n", + "成功获取 688298.SH 的数据\n", + "成功获取 688299.SH 的数据\n", + "成功获取 688300.SH 的数据\n", + "成功获取 688301.SH 的数据\n", + "成功获取 688302.SH 的数据\n", + "成功获取 688303.SH 的数据\n", + "成功获取 688305.SH 的数据\n", + "成功获取 688306.SH 的数据\n", + "成功获取 688307.SH 的数据\n", + "成功获取 688308.SH 的数据\n", + "成功获取 688309.SH 的数据\n", + "成功获取 688310.SH 的数据\n", + "成功获取 688311.SH 的数据\n", + "成功获取 688312.SH 的数据\n", + "成功获取 688313.SH 的数据\n", + "成功获取 688314.SH 的数据\n", + "成功获取 688315.SH 的数据\n", + "成功获取 688316.SH 的数据\n", + "成功获取 688317.SH 的数据\n", + "成功获取 688318.SH 的数据\n", + "成功获取 688319.SH 的数据\n", + "成功获取 688320.SH 的数据\n", + "成功获取 688321.SH 的数据\n", + "成功获取 688322.SH 的数据\n", + "成功获取 688323.SH 的数据\n", + "成功获取 688325.SH 的数据\n", + "成功获取 688326.SH 的数据\n", + "成功获取 688327.SH 的数据\n", + "成功获取 688328.SH 的数据\n", + "成功获取 688329.SH 的数据\n", + "成功获取 688330.SH 的数据\n", + "成功获取 688331.SH 的数据\n", + "成功获取 688332.SH 的数据\n", + "成功获取 688333.SH 的数据\n", + "成功获取 688334.SH 的数据\n", + "成功获取 688335.SH 的数据\n", + "成功获取 688336.SH 的数据\n", + "成功获取 688337.SH 的数据\n", + "成功获取 688338.SH 的数据\n", + "成功获取 688339.SH 的数据\n", + "成功获取 688343.SH 的数据\n", + "成功获取 688345.SH 的数据\n", + "成功获取 688347.SH 的数据\n", + "成功获取 688348.SH 的数据\n", + "成功获取 688349.SH 的数据\n", + "成功获取 688350.SH 的数据\n", + "成功获取 688351.SH 的数据\n", + "成功获取 688352.SH 的数据\n", + "成功获取 688353.SH 的数据\n", + "成功获取 688355.SH 的数据\n", + "成功获取 688356.SH 的数据\n", + "成功获取 688357.SH 的数据\n", + "成功获取 688358.SH 的数据\n", + "成功获取 688359.SH 的数据\n", + "成功获取 688360.SH 的数据\n", + "成功获取 688361.SH 的数据\n", + "成功获取 688362.SH 的数据\n", + "成功获取 688363.SH 的数据\n", + "成功获取 688365.SH 的数据\n", + "成功获取 688366.SH 的数据\n", + "成功获取 688367.SH 的数据\n", + "成功获取 688368.SH 的数据\n", + "成功获取 688369.SH 的数据\n", + "成功获取 688370.SH 的数据\n", + "成功获取 688371.SH 的数据\n", + "成功获取 688372.SH 的数据\n", + "成功获取 688373.SH 的数据\n", + "成功获取 688375.SH 的数据\n", + "成功获取 688376.SH 的数据\n", + "成功获取 688377.SH 的数据\n", + "成功获取 688378.SH 的数据\n", + "成功获取 688379.SH 的数据\n", + "成功获取 688380.SH 的数据\n", + "成功获取 688381.SH 的数据\n", + "成功获取 688382.SH 的数据\n", + "成功获取 688383.SH 的数据\n", + "成功获取 688385.SH 的数据\n", + "成功获取 688386.SH 的数据\n", + "成功获取 688387.SH 的数据\n", + "成功获取 688388.SH 的数据\n", + "成功获取 688389.SH 的数据\n", + "成功获取 688390.SH 的数据\n", + "成功获取 688391.SH 的数据\n", + "成功获取 688392.SH 的数据\n", + "成功获取 688393.SH 的数据\n", + "成功获取 688395.SH 的数据\n", + "成功获取 688396.SH 的数据\n", + "成功获取 688398.SH 的数据\n", + "成功获取 688399.SH 的数据\n", + "成功获取 688400.SH 的数据\n", + "成功获取 688401.SH 的数据\n", + "成功获取 688403.SH 的数据\n", + "成功获取 688408.SH 的数据\n", + "成功获取 688409.SH 的数据\n", + "成功获取 688410.SH 的数据\n", + "成功获取 688411.SH 的数据\n", + "成功获取 688416.SH 的数据\n", + "成功获取 688418.SH 的数据\n", + "成功获取 688419.SH 的数据\n", + "成功获取 688420.SH 的数据\n", + "成功获取 688425.SH 的数据\n", + "成功获取 688426.SH 的数据\n", + "成功获取 688428.SH 的数据\n", + "成功获取 688429.SH 的数据\n", + "成功获取 688432.SH 的数据\n", + "成功获取 688433.SH 的数据\n", + "成功获取 688435.SH 的数据\n", + "成功获取 688439.SH 的数据\n", + "成功获取 688443.SH 的数据\n", + "成功获取 688448.SH 的数据\n", + "成功获取 688449.SH 的数据\n", + "成功获取 688450.SH 的数据\n", + "成功获取 688455.SH 的数据\n", + "成功获取 688456.SH 的数据\n", + "成功获取 688458.SH 的数据\n", + "成功获取 688459.SH 的数据\n", + "成功获取 688466.SH 的数据\n", + "成功获取 688468.SH 的数据\n", + "成功获取 688469.SH 的数据\n", + "成功获取 688472.SH 的数据\n", + "成功获取 688475.SH 的数据\n", + "成功获取 688478.SH 的数据\n", + "成功获取 688479.SH 的数据\n", + "成功获取 688480.SH 的数据\n", + "成功获取 688484.SH 的数据\n", + "成功获取 688485.SH 的数据\n", + "成功获取 688486.SH 的数据\n", + "成功获取 688488.SH 的数据\n", + "成功获取 688489.SH 的数据\n", + "成功获取 688496.SH 的数据\n", + "成功获取 688498.SH 的数据\n", + "成功获取 688499.SH 的数据\n", + "成功获取 688500.SH 的数据\n", + "成功获取 688501.SH 的数据\n", + "成功获取 688502.SH 的数据\n", + "成功获取 688503.SH 的数据\n", + "成功获取 688505.SH 的数据\n", + "成功获取 688506.SH 的数据\n", + "成功获取 688507.SH 的数据\n", + "成功获取 688508.SH 的数据\n", + "成功获取 688509.SH 的数据\n", + "成功获取 688510.SH 的数据\n", + "成功获取 688511.SH 的数据\n", + "成功获取 688512.SH 的数据\n", + "成功获取 688513.SH 的数据\n", + "成功获取 688515.SH 的数据\n", + "成功获取 688516.SH 的数据\n", + "成功获取 688517.SH 的数据\n", + "成功获取 688518.SH 的数据\n", + "成功获取 688519.SH 的数据\n", + "成功获取 688520.SH 的数据\n", + "成功获取 688521.SH 的数据\n", + "成功获取 688522.SH 的数据\n", + "成功获取 688523.SH 的数据\n", + "成功获取 688525.SH 的数据\n", + "成功获取 688526.SH 的数据\n", + "成功获取 688528.SH 的数据\n", + "成功获取 688529.SH 的数据\n", + "成功获取 688530.SH 的数据\n", + "成功获取 688531.SH 的数据\n", + "成功获取 688533.SH 的数据\n", + "成功获取 688535.SH 的数据\n", + "成功获取 688536.SH 的数据\n", + "成功获取 688538.SH 的数据\n", + "成功获取 688539.SH 的数据\n", + "成功获取 688543.SH 的数据\n", + "成功获取 688545.SH 的数据\n", + "成功获取 688548.SH 的数据\n", + "成功获取 688549.SH 的数据\n", + "成功获取 688550.SH 的数据\n", + "成功获取 688551.SH 的数据\n", + "成功获取 688552.SH 的数据\n", + "成功获取 688553.SH 的数据\n", + "成功获取 688556.SH 的数据\n", + "成功获取 688557.SH 的数据\n", + "成功获取 688558.SH 的数据\n", + "成功获取 688559.SH 的数据\n", + "成功获取 688560.SH 的数据\n", + "成功获取 688561.SH 的数据\n", + "成功获取 688562.SH 的数据\n", + "成功获取 688563.SH 的数据\n", + "成功获取 688565.SH 的数据\n", + "成功获取 688566.SH 的数据\n", + "成功获取 688567.SH 的数据\n", + "成功获取 688568.SH 的数据\n", + "成功获取 688569.SH 的数据\n", + "成功获取 688570.SH 的数据\n", + "成功获取 688571.SH 的数据\n", + "成功获取 688573.SH 的数据\n", + "成功获取 688575.SH 的数据\n", + "成功获取 688576.SH 的数据\n", + "成功获取 688577.SH 的数据\n", + "成功获取 688578.SH 的数据\n", + "成功获取 688579.SH 的数据\n", + "成功获取 688580.SH 的数据\n", + "成功获取 688581.SH 的数据\n", + "成功获取 688582.SH 的数据\n", + "成功获取 688583.SH 的数据\n", + "成功获取 688584.SH 的数据\n", + "成功获取 688585.SH 的数据\n", + "成功获取 688586.SH 的数据\n", + "成功获取 688588.SH 的数据\n", + "成功获取 688589.SH 的数据\n", + "成功获取 688590.SH 的数据\n", + "成功获取 688591.SH 的数据\n", + "成功获取 688592.SH 的数据\n", + "成功获取 688593.SH 的数据\n", + "成功获取 688595.SH 的数据\n", + "成功获取 688596.SH 的数据\n", + "成功获取 688597.SH 的数据\n", + "成功获取 688598.SH 的数据\n", + "成功获取 688599.SH 的数据\n", + "成功获取 688600.SH 的数据\n", + "成功获取 688601.SH 的数据\n", + "成功获取 688602.SH 的数据\n", + "成功获取 688603.SH 的数据\n", + "成功获取 688605.SH 的数据\n", + "成功获取 688606.SH 的数据\n", + "成功获取 688607.SH 的数据\n", + "成功获取 688608.SH 的数据\n", + "成功获取 688609.SH 的数据\n", + "成功获取 688610.SH 的数据\n", + "成功获取 688611.SH 的数据\n", + "成功获取 688612.SH 的数据\n", + "成功获取 688613.SH 的数据\n", + "成功获取 688615.SH 的数据\n", + "成功获取 688616.SH 的数据\n", + "成功获取 688617.SH 的数据\n", + "成功获取 688618.SH 的数据\n", + "成功获取 688619.SH 的数据\n", + "成功获取 688620.SH 的数据\n", + "成功获取 688621.SH 的数据\n", + "成功获取 688622.SH 的数据\n", + "成功获取 688623.SH 的数据\n", + "成功获取 688625.SH 的数据\n", + "成功获取 688626.SH 的数据\n", + "成功获取 688627.SH 的数据\n", + "成功获取 688628.SH 的数据\n", + "成功获取 688629.SH 的数据\n", + "成功获取 688630.SH 的数据\n", + "成功获取 688631.SH 的数据\n", + "成功获取 688633.SH 的数据\n", + "成功获取 688636.SH 的数据\n", + "成功获取 688638.SH 的数据\n", + "成功获取 688639.SH 的数据\n", + "成功获取 688646.SH 的数据\n", + "成功获取 688648.SH 的数据\n", + "成功获取 688651.SH 的数据\n", + "成功获取 688652.SH 的数据\n", + "成功获取 688653.SH 的数据\n", + "成功获取 688655.SH 的数据\n", + "成功获取 688656.SH 的数据\n", + "成功获取 688657.SH 的数据\n", + "成功获取 688658.SH 的数据\n", + "成功获取 688659.SH 的数据\n", + "成功获取 688660.SH 的数据\n", + "成功获取 688661.SH 的数据\n", + "成功获取 688662.SH 的数据\n", + "成功获取 688663.SH 的数据\n", + "成功获取 688665.SH 的数据\n", + "成功获取 688667.SH 的数据\n", + "成功获取 688668.SH 的数据\n", + "成功获取 688669.SH 的数据\n", + "成功获取 688670.SH 的数据\n", + "成功获取 688671.SH 的数据\n", + "成功获取 688676.SH 的数据\n", + "成功获取 688677.SH 的数据\n", + "成功获取 688678.SH 的数据\n", + "成功获取 688679.SH 的数据\n", + "成功获取 688680.SH 的数据\n", + "成功获取 688681.SH 的数据\n", + "成功获取 688682.SH 的数据\n", + "成功获取 688683.SH 的数据\n", + "成功获取 688685.SH 的数据\n", + "成功获取 688686.SH 的数据\n", + "成功获取 688687.SH 的数据\n", + "成功获取 688689.SH 的数据\n", + "成功获取 688690.SH 的数据\n", + "成功获取 688691.SH 的数据\n", + "已调用300次API,等待 11.66 秒以满足速率限制...\n", + "成功获取 688692.SH 的数据\n", + "成功获取 688693.SH 的数据\n", + "成功获取 688695.SH 的数据\n", + "成功获取 688696.SH 的数据\n", + "成功获取 688697.SH 的数据\n", + "成功获取 688698.SH 的数据\n", + "成功获取 688699.SH 的数据\n", + "成功获取 688700.SH 的数据\n", + "成功获取 688701.SH 的数据\n", + "成功获取 688702.SH 的数据\n", + "成功获取 688707.SH 的数据\n", + "成功获取 688708.SH 的数据\n", + "成功获取 688709.SH 的数据\n", + "成功获取 688710.SH 的数据\n", + "成功获取 688711.SH 的数据\n", + "成功获取 688716.SH 的数据\n", + "成功获取 688717.SH 的数据\n", + "成功获取 688718.SH 的数据\n", + "成功获取 688719.SH 的数据\n", + "成功获取 688720.SH 的数据\n", + "成功获取 688721.SH 的数据\n", + "成功获取 688722.SH 的数据\n", + "成功获取 688726.SH 的数据\n", + "成功获取 688728.SH 的数据\n", + "成功获取 688733.SH 的数据\n", + "成功获取 688737.SH 的数据\n", + "成功获取 688739.SH 的数据\n", + "成功获取 688750.SH 的数据\n", + "成功获取 688758.SH 的数据\n", + "成功获取 688766.SH 的数据\n", + "成功获取 688767.SH 的数据\n", + "成功获取 688768.SH 的数据\n", + "成功获取 688772.SH 的数据\n", + "成功获取 688776.SH 的数据\n", + "成功获取 688777.SH 的数据\n", + "成功获取 688778.SH 的数据\n", + "成功获取 688779.SH 的数据\n", + "成功获取 688786.SH 的数据\n", + "成功获取 688787.SH 的数据\n", + "成功获取 688788.SH 的数据\n", + "成功获取 688789.SH 的数据\n", + "成功获取 688793.SH 的数据\n", + "成功获取 688798.SH 的数据\n", + "成功获取 688799.SH 的数据\n", + "成功获取 688800.SH 的数据\n", + "成功获取 688819.SH 的数据\n", + "成功获取 688981.SH 的数据\n", + "成功获取 830779.BJ 的数据\n", + "成功获取 830799.BJ 的数据\n", + "成功获取 830809.BJ 的数据\n", + "成功获取 830832.BJ 的数据\n", + "成功获取 830839.BJ 的数据\n", + "成功获取 830879.BJ 的数据\n", + "成功获取 830896.BJ 的数据\n", + "成功获取 830946.BJ 的数据\n", + "成功获取 830964.BJ 的数据\n", + "成功获取 830974.BJ 的数据\n", + "成功获取 831010.BJ 的数据\n", + "成功获取 831039.BJ 的数据\n", + "成功获取 831087.BJ 的数据\n", + "成功获取 831152.BJ 的数据\n", + "成功获取 831167.BJ 的数据\n", + "成功获取 831175.BJ 的数据\n", + "成功获取 831195.BJ 的数据\n", + "成功获取 831278.BJ 的数据\n", + "成功获取 831304.BJ 的数据\n", + "成功获取 831305.BJ 的数据\n", + "成功获取 831370.BJ 的数据\n", + "成功获取 831396.BJ 的数据\n", + "成功获取 831445.BJ 的数据\n", + "成功获取 831526.BJ 的数据\n", + "成功获取 831627.BJ 的数据\n", + "成功获取 831641.BJ 的数据\n", + "成功获取 831689.BJ 的数据\n", + "成功获取 831726.BJ 的数据\n", + "成功获取 831768.BJ 的数据\n", + "成功获取 831832.BJ 的数据\n", + "成功获取 831834.BJ 的数据\n", + "成功获取 831855.BJ 的数据\n", + "成功获取 831856.BJ 的数据\n", + "成功获取 831906.BJ 的数据\n", + "成功获取 831961.BJ 的数据\n", + "成功获取 832000.BJ 的数据\n", + "成功获取 832023.BJ 的数据\n", + "成功获取 832089.BJ 的数据\n", + "成功获取 832110.BJ 的数据\n", + "成功获取 832145.BJ 的数据\n", + "成功获取 832149.BJ 的数据\n", + "成功获取 832171.BJ 的数据\n", + "成功获取 832175.BJ 的数据\n", + "成功获取 832225.BJ 的数据\n", + "成功获取 832278.BJ 的数据\n", + "成功获取 832419.BJ 的数据\n", + "成功获取 832469.BJ 的数据\n", + "成功获取 832471.BJ 的数据\n", + "成功获取 832491.BJ 的数据\n", + "成功获取 832522.BJ 的数据\n", + "成功获取 832566.BJ 的数据\n", + "成功获取 832651.BJ 的数据\n", + "成功获取 832662.BJ 的数据\n", + "成功获取 832735.BJ 的数据\n", + "成功获取 832786.BJ 的数据\n", + "成功获取 832802.BJ 的数据\n", + "成功获取 832876.BJ 的数据\n", + "成功获取 832885.BJ 的数据\n", + "成功获取 832978.BJ 的数据\n", + "成功获取 832982.BJ 的数据\n", + "成功获取 833030.BJ 的数据\n", + "成功获取 833075.BJ 的数据\n", + "成功获取 833171.BJ 的数据\n", + "成功获取 833230.BJ 的数据\n", + "成功获取 833266.BJ 的数据\n", + "成功获取 833284.BJ 的数据\n", + "成功获取 833346.BJ 的数据\n", + "成功获取 833394.BJ 的数据\n", + "成功获取 833427.BJ 的数据\n", + "成功获取 833429.BJ 的数据\n", + "成功获取 833454.BJ 的数据\n", + "成功获取 833455.BJ 的数据\n", + "成功获取 833509.BJ 的数据\n", + "成功获取 833523.BJ 的数据\n", + "成功获取 833533.BJ 的数据\n", + "成功获取 833575.BJ 的数据\n", + "成功获取 833580.BJ 的数据\n", + "成功获取 833751.BJ 的数据\n", + "成功获取 833781.BJ 的数据\n", + "成功获取 833819.BJ 的数据\n", + "成功获取 833873.BJ 的数据\n", + "成功获取 833914.BJ 的数据\n", + "成功获取 833943.BJ 的数据\n", + "成功获取 834014.BJ 的数据\n", + "成功获取 834021.BJ 的数据\n", + "成功获取 834033.BJ 的数据\n", + "成功获取 834058.BJ 的数据\n", + "成功获取 834062.BJ 的数据\n", + "成功获取 834261.BJ 的数据\n", + "成功获取 834407.BJ 的数据\n", + "成功获取 834415.BJ 的数据\n", + "成功获取 834475.BJ 的数据\n", + "成功获取 834599.BJ 的数据\n", + "成功获取 834639.BJ 的数据\n", + "成功获取 834682.BJ 的数据\n", + "成功获取 834765.BJ 的数据\n", + "成功获取 834770.BJ 的数据\n", + "成功获取 834950.BJ 的数据\n", + "成功获取 835174.BJ 的数据\n", + "成功获取 835179.BJ 的数据\n", + "成功获取 835184.BJ 的数据\n", + "成功获取 835185.BJ 的数据\n", + "成功获取 835207.BJ 的数据\n", + "成功获取 835237.BJ 的数据\n", + "成功获取 835305.BJ 的数据\n", + "成功获取 835368.BJ 的数据\n", + "成功获取 835438.BJ 的数据\n", + "成功获取 835508.BJ 的数据\n", + "成功获取 835579.BJ 的数据\n", + "成功获取 835640.BJ 的数据\n", + "成功获取 835670.BJ 的数据\n", + "成功获取 835857.BJ 的数据\n", + "成功获取 835892.BJ 的数据\n", + "成功获取 835985.BJ 的数据\n", + "成功获取 836077.BJ 的数据\n", + "成功获取 836149.BJ 的数据\n", + "成功获取 836208.BJ 的数据\n", + "成功获取 836221.BJ 的数据\n", + "成功获取 836239.BJ 的数据\n", + "成功获取 836247.BJ 的数据\n", + "成功获取 836260.BJ 的数据\n", + "成功获取 836263.BJ 的数据\n", + "成功获取 836270.BJ 的数据\n", + "成功获取 836395.BJ 的数据\n", + "成功获取 836414.BJ 的数据\n", + "成功获取 836419.BJ 的数据\n", + "成功获取 836422.BJ 的数据\n", + "成功获取 836433.BJ 的数据\n", + "成功获取 836504.BJ 的数据\n", + "成功获取 836547.BJ 的数据\n", + "成功获取 836675.BJ 的数据\n", + "成功获取 836699.BJ 的数据\n", + "成功获取 836717.BJ 的数据\n", + "成功获取 836720.BJ 的数据\n", + "成功获取 836807.BJ 的数据\n", + "成功获取 836826.BJ 的数据\n", + "成功获取 836871.BJ 的数据\n", + "成功获取 836892.BJ 的数据\n", + "成功获取 836942.BJ 的数据\n", + "成功获取 836957.BJ 的数据\n", + "成功获取 836961.BJ 的数据\n", + "成功获取 837006.BJ 的数据\n", + "成功获取 837023.BJ 的数据\n", + "成功获取 837046.BJ 的数据\n", + "成功获取 837092.BJ 的数据\n", + "成功获取 837174.BJ 的数据\n", + "成功获取 837212.BJ 的数据\n", + "成功获取 837242.BJ 的数据\n", + "成功获取 837344.BJ 的数据\n", + "成功获取 837403.BJ 的数据\n", + "成功获取 837592.BJ 的数据\n", + "成功获取 837663.BJ 的数据\n", + "成功获取 837748.BJ 的数据\n", + "成功获取 837821.BJ 的数据\n", + "成功获取 838030.BJ 的数据\n", + "成功获取 838163.BJ 的数据\n", + "成功获取 838171.BJ 的数据\n", + "成功获取 838227.BJ 的数据\n", + "成功获取 838262.BJ 的数据\n", + "成功获取 838275.BJ 的数据\n", + "成功获取 838402.BJ 的数据\n", + "成功获取 838670.BJ 的数据\n", + "成功获取 838701.BJ 的数据\n", + "成功获取 838810.BJ 的数据\n", + "成功获取 838837.BJ 的数据\n", + "成功获取 838924.BJ 的数据\n", + "成功获取 838971.BJ 的数据\n", + "成功获取 839167.BJ 的数据\n", + "成功获取 839273.BJ 的数据\n", + "成功获取 839371.BJ 的数据\n", + "成功获取 839493.BJ 的数据\n", + "成功获取 839680.BJ 的数据\n", + "成功获取 839719.BJ 的数据\n", + "成功获取 839725.BJ 的数据\n", + "成功获取 839729.BJ 的数据\n", + "成功获取 839790.BJ 的数据\n", + "成功获取 839792.BJ 的数据\n", + "成功获取 839946.BJ 的数据\n", + "成功获取 870199.BJ 的数据\n", + "成功获取 870204.BJ 的数据\n", + "成功获取 870299.BJ 的数据\n", + "成功获取 870357.BJ 的数据\n", + "成功获取 870436.BJ 的数据\n", + "成功获取 870508.BJ 的数据\n", + "成功获取 870656.BJ 的数据\n", + "成功获取 870726.BJ 的数据\n", + "成功获取 870866.BJ 的数据\n", + "成功获取 870976.BJ 的数据\n", + "成功获取 871245.BJ 的数据\n", + "成功获取 871263.BJ 的数据\n", + "成功获取 871396.BJ 的数据\n", + "成功获取 871478.BJ 的数据\n", + "成功获取 871553.BJ 的数据\n", + "成功获取 871634.BJ 的数据\n", + "成功获取 871642.BJ 的数据\n", + "成功获取 871694.BJ 的数据\n", + "成功获取 871753.BJ 的数据\n", + "成功获取 871857.BJ 的数据\n", + "成功获取 871970.BJ 的数据\n", + "成功获取 871981.BJ 的数据\n", + "成功获取 872190.BJ 的数据\n", + "成功获取 872351.BJ 的数据\n", + "成功获取 872374.BJ 的数据\n", + "成功获取 872392.BJ 的数据\n", + "成功获取 872541.BJ 的数据\n", + "成功获取 872808.BJ 的数据\n", + "成功获取 872895.BJ 的数据\n", + "成功获取 872925.BJ 的数据\n", + "成功获取 872931.BJ 的数据\n", + "成功获取 872953.BJ 的数据\n", + "成功获取 873001.BJ 的数据\n", + "成功获取 873122.BJ 的数据\n", + "成功获取 873132.BJ 的数据\n", + "成功获取 873152.BJ 的数据\n", + "成功获取 873167.BJ 的数据\n", + "成功获取 873169.BJ 的数据\n", + "成功获取 873223.BJ 的数据\n", + "成功获取 873305.BJ 的数据\n", + "成功获取 873339.BJ 的数据\n", + "成功获取 873527.BJ 的数据\n", + "成功获取 873570.BJ 的数据\n", + "成功获取 873576.BJ 的数据\n", + "成功获取 873593.BJ 的数据\n", + "成功获取 873665.BJ 的数据\n", + "成功获取 873679.BJ 的数据\n", + "成功获取 873690.BJ 的数据\n", + "成功获取 873693.BJ 的数据\n", + "成功获取 873703.BJ 的数据\n", + "成功获取 873706.BJ 的数据\n", + "成功获取 873726.BJ 的数据\n", + "成功获取 873806.BJ 的数据\n", + "成功获取 873833.BJ 的数据\n", + "成功获取 920002.BJ 的数据\n", + "成功获取 920008.BJ 的数据\n", + "成功获取 920016.BJ 的数据\n", + "成功获取 920019.BJ 的数据\n", + "成功获取 920060.BJ 的数据\n", + "成功获取 920066.BJ 的数据\n", + "成功获取 920082.BJ 的数据\n", + "成功获取 920088.BJ 的数据\n", + "成功获取 920098.BJ 的数据\n", + "成功获取 920099.BJ 的数据\n", + "成功获取 920106.BJ 的数据\n", + "成功获取 920108.BJ 的数据\n", + "成功获取 920111.BJ 的数据\n", + "成功获取 920116.BJ 的数据\n", + "成功获取 920118.BJ 的数据\n", + "成功获取 920128.BJ 的数据\n", + "成功获取 689009.SH 的数据\n", + "成功获取 000003.SZ 的数据\n", + "成功获取 000005.SZ 的数据\n", + "成功获取 000013.SZ 的数据\n", + "成功获取 000015.SZ 的数据\n", + "已调用300次API,等待 13.36 秒以满足速率限制...\n", + "成功获取 000018.SZ 的数据\n", + "成功获取 000023.SZ 的数据\n", + "成功获取 000024.SZ 的数据\n", + "成功获取 000033.SZ 的数据\n", + "成功获取 000038.SZ 的数据\n", + "成功获取 000046.SZ 的数据\n", + "成功获取 000047.SZ 的数据\n", + "成功获取 000150.SZ 的数据\n", + "成功获取 000405.SZ 的数据\n", + "成功获取 000406.SZ 的数据\n", + "成功获取 000412.SZ 的数据\n", + "成功获取 000413.SZ 的数据\n", + "成功获取 000416.SZ 的数据\n", + "成功获取 000418.SZ 的数据\n", + "成功获取 000502.SZ 的数据\n", + "成功获取 000508.SZ 的数据\n", + "成功获取 000511.SZ 的数据\n", + "成功获取 000515.SZ 的数据\n", + "成功获取 000522.SZ 的数据\n", + "成功获取 000527.SZ 的数据\n", + "成功获取 000535.SZ 的数据\n", + "成功获取 000540.SZ 的数据\n", + "成功获取 000542.SZ 的数据\n", + "成功获取 000549.SZ 的数据\n", + "成功获取 000556.SZ 的数据\n", + "成功获取 000562.SZ 的数据\n", + "成功获取 000569.SZ 的数据\n", + "成功获取 000578.SZ 的数据\n", + "成功获取 000583.SZ 的数据\n", + "成功获取 000585.SZ 的数据\n", + "成功获取 000587.SZ 的数据\n", + "成功获取 000588.SZ 的数据\n", + "成功获取 000594.SZ 的数据\n", + "成功获取 000602.SZ 的数据\n", + "成功获取 000606.SZ 的数据\n", + "成功获取 000611.SZ 的数据\n", + "成功获取 000613.SZ 的数据\n", + "成功获取 000616.SZ 的数据\n", + "成功获取 000618.SZ 的数据\n", + "成功获取 000621.SZ 的数据\n", + "成功获取 000653.SZ 的数据\n", + "成功获取 000658.SZ 的数据\n", + "成功获取 000660.SZ 的数据\n", + "成功获取 000662.SZ 的数据\n", + "成功获取 000666.SZ 的数据\n", + "成功获取 000667.SZ 的数据\n", + "成功获取 000671.SZ 的数据\n", + "成功获取 000673.SZ 的数据\n", + "成功获取 000675.SZ 的数据\n", + "成功获取 000687.SZ 的数据\n", + "成功获取 000689.SZ 的数据\n", + "成功获取 000693.SZ 的数据\n", + "成功获取 000699.SZ 的数据\n", + "成功获取 000730.SZ 的数据\n", + "成功获取 000732.SZ 的数据\n", + "成功获取 000748.SZ 的数据\n", + "成功获取 000760.SZ 的数据\n", + "成功获取 000763.SZ 的数据\n", + "成功获取 000765.SZ 的数据\n", + "成功获取 000769.SZ 的数据\n", + "成功获取 000780.SZ 的数据\n", + "成功获取 000787.SZ 的数据\n", + "成功获取 000805.SZ 的数据\n", + "成功获取 000806.SZ 的数据\n", + "成功获取 000817.SZ 的数据\n", + "成功获取 000827.SZ 的数据\n", + "成功获取 000832.SZ 的数据\n", + "成功获取 000835.SZ 的数据\n", + "成功获取 000836.SZ 的数据\n", + "成功获取 000861.SZ 的数据\n", + "成功获取 000866.SZ 的数据\n", + "成功获取 000916.SZ 的数据\n", + "成功获取 000918.SZ 的数据\n", + "成功获取 000939.SZ 的数据\n", + "成功获取 000956.SZ 的数据\n", + "成功获取 000961.SZ 的数据\n", + "成功获取 000971.SZ 的数据\n", + "成功获取 000976.SZ 的数据\n", + "成功获取 000979.SZ 的数据\n", + "成功获取 000982.SZ 的数据\n", + "成功获取 000996.SZ 的数据\n", + "成功获取 002002.SZ 的数据\n", + "成功获取 002013.SZ 的数据\n", + "成功获取 002018.SZ 的数据\n", + "成功获取 002070.SZ 的数据\n", + "成功获取 002071.SZ 的数据\n", + "成功获取 002087.SZ 的数据\n", + "成功获取 002089.SZ 的数据\n", + "成功获取 002113.SZ 的数据\n", + "成功获取 002118.SZ 的数据\n", + "成功获取 002143.SZ 的数据\n", + "成功获取 002147.SZ 的数据\n", + "成功获取 002220.SZ 的数据\n", + "成功获取 002260.SZ 的数据\n", + "成功获取 002280.SZ 的数据\n", + "成功获取 002288.SZ 的数据\n", + "成功获取 002308.SZ 的数据\n", + "成功获取 002325.SZ 的数据\n", + "成功获取 002341.SZ 的数据\n", + "成功获取 002359.SZ 的数据\n", + "成功获取 002411.SZ 的数据\n", + "成功获取 002417.SZ 的数据\n", + "成功获取 002433.SZ 的数据\n", + "成功获取 002435.SZ 的数据\n", + "成功获取 002447.SZ 的数据\n", + "成功获取 002450.SZ 的数据\n", + "成功获取 002464.SZ 的数据\n", + "成功获取 002473.SZ 的数据\n", + "成功获取 002477.SZ 的数据\n", + "成功获取 002499.SZ 的数据\n", + "成功获取 002502.SZ 的数据\n", + "成功获取 002503.SZ 的数据\n", + "成功获取 002504.SZ 的数据\n", + "成功获取 002505.SZ 的数据\n", + "成功获取 002509.SZ 的数据\n", + "成功获取 002604.SZ 的数据\n", + "成功获取 002610.SZ 的数据\n", + "成功获取 002618.SZ 的数据\n", + "成功获取 002619.SZ 的数据\n", + "成功获取 002621.SZ 的数据\n", + "成功获取 002665.SZ 的数据\n", + "成功获取 002680.SZ 的数据\n", + "成功获取 002684.SZ 的数据\n", + "成功获取 002699.SZ 的数据\n", + "成功获取 002711.SZ 的数据\n", + "成功获取 002740.SZ 的数据\n", + "成功获取 002751.SZ 的数据\n", + "成功获取 002770.SZ 的数据\n", + "成功获取 002776.SZ 的数据\n", + "成功获取 002781.SZ 的数据\n", + "成功获取 300023.SZ 的数据\n", + "成功获取 300028.SZ 的数据\n", + "成功获取 300038.SZ 的数据\n", + "成功获取 300064.SZ 的数据\n", + "成功获取 300089.SZ 的数据\n", + "成功获取 300090.SZ 的数据\n", + "成功获取 300104.SZ 的数据\n", + "成功获取 300116.SZ 的数据\n", + "成功获取 300156.SZ 的数据\n", + "成功获取 300178.SZ 的数据\n", + "成功获取 300186.SZ 的数据\n", + "成功获取 300202.SZ 的数据\n", + "成功获取 300216.SZ 的数据\n", + "成功获取 300262.SZ 的数据\n", + "成功获取 300273.SZ 的数据\n", + "成功获取 300282.SZ 的数据\n", + "成功获取 300297.SZ 的数据\n", + "成功获取 300309.SZ 的数据\n", + "成功获取 300312.SZ 的数据\n", + "成功获取 300325.SZ 的数据\n", + "成功获取 300330.SZ 的数据\n", + "成功获取 300336.SZ 的数据\n", + "成功获取 300356.SZ 的数据\n", + "成功获取 300362.SZ 的数据\n", + "成功获取 300367.SZ 的数据\n", + "成功获取 300372.SZ 的数据\n", + "成功获取 300392.SZ 的数据\n", + "成功获取 300431.SZ 的数据\n", + "成功获取 300495.SZ 的数据\n", + "成功获取 300526.SZ 的数据\n", + "成功获取 300742.SZ 的数据\n", + "成功获取 300799.SZ 的数据\n", + "成功获取 600001.SH 的数据\n", + "成功获取 600002.SH 的数据\n", + "成功获取 600003.SH 的数据\n", + "成功获取 600005.SH 的数据\n", + "成功获取 600065.SH 的数据\n", + "成功获取 600068.SH 的数据\n", + "成功获取 600069.SH 的数据\n", + "成功获取 600074.SH 的数据\n", + "成功获取 600077.SH 的数据\n", + "成功获取 600086.SH 的数据\n", + "成功获取 600087.SH 的数据\n", + "成功获取 600090.SH 的数据\n", + "成功获取 600091.SH 的数据\n", + "成功获取 600092.SH 的数据\n", + "成功获取 600093.SH 的数据\n", + "成功获取 600102.SH 的数据\n", + "成功获取 600112.SH 的数据\n", + "成功获取 600122.SH 的数据\n", + "成功获取 600139.SH 的数据\n", + "成功获取 600145.SH 的数据\n", + "成功获取 600146.SH 的数据\n", + "成功获取 600175.SH 的数据\n", + "成功获取 600181.SH 的数据\n", + "成功获取 600205.SH 的数据\n", + "成功获取 600209.SH 的数据\n", + "成功获取 600213.SH 的数据\n", + "成功获取 600220.SH 的数据\n", + "成功获取 600240.SH 的数据\n", + "成功获取 600242.SH 的数据\n", + "成功获取 600247.SH 的数据\n", + "成功获取 600253.SH 的数据\n", + "成功获取 600260.SH 的数据\n", + "成功获取 600263.SH 的数据\n", + "成功获取 600270.SH 的数据\n", + "成功获取 600275.SH 的数据\n", + "成功获取 600277.SH 的数据\n", + "成功获取 600286.SH 的数据\n", + "成功获取 600290.SH 的数据\n", + "成功获取 600291.SH 的数据\n", + "成功获取 600296.SH 的数据\n", + "成功获取 600297.SH 的数据\n", + "成功获取 600306.SH 的数据\n", + "成功获取 600311.SH 的数据\n", + "成功获取 600317.SH 的数据\n", + "成功获取 600321.SH 的数据\n", + "成功获取 600357.SH 的数据\n", + "成功获取 600385.SH 的数据\n", + "成功获取 600393.SH 的数据\n", + "成功获取 600401.SH 的数据\n", + "成功获取 600432.SH 的数据\n", + "成功获取 600466.SH 的数据\n", + "成功获取 600472.SH 的数据\n", + "成功获取 600485.SH 的数据\n", + "成功获取 600532.SH 的数据\n", + "成功获取 600553.SH 的数据\n", + "成功获取 600555.SH 的数据\n", + "成功获取 600565.SH 的数据\n", + "成功获取 600591.SH 的数据\n", + "成功获取 600607.SH 的数据\n", + "成功获取 600614.SH 的数据\n", + "成功获取 600625.SH 的数据\n", + "成功获取 600627.SH 的数据\n", + "成功获取 600631.SH 的数据\n", + "成功获取 600632.SH 的数据\n", + "成功获取 600634.SH 的数据\n", + "成功获取 600646.SH 的数据\n", + "成功获取 600647.SH 的数据\n", + "成功获取 600652.SH 的数据\n", + "成功获取 600656.SH 的数据\n", + "成功获取 600659.SH 的数据\n", + "成功获取 600669.SH 的数据\n", + "成功获取 600670.SH 的数据\n", + "成功获取 600672.SH 的数据\n", + "成功获取 600677.SH 的数据\n", + "成功获取 600680.SH 的数据\n", + "成功获取 600687.SH 的数据\n", + "成功获取 600695.SH 的数据\n", + "成功获取 600700.SH 的数据\n", + "成功获取 600701.SH 的数据\n", + "成功获取 600709.SH 的数据\n", + "成功获取 600723.SH 的数据\n", + "成功获取 600747.SH 的数据\n", + "成功获取 600752.SH 的数据\n", + "成功获取 600762.SH 的数据\n", + "成功获取 600766.SH 的数据\n", + "成功获取 600767.SH 的数据\n", + "成功获取 600772.SH 的数据\n", + "成功获取 600781.SH 的数据\n", + "成功获取 600786.SH 的数据\n", + "成功获取 600788.SH 的数据\n", + "成功获取 600799.SH 的数据\n", + "成功获取 600806.SH 的数据\n", + "成功获取 600813.SH 的数据\n", + "成功获取 600823.SH 的数据\n", + "成功获取 600832.SH 的数据\n", + "成功获取 600836.SH 的数据\n", + "成功获取 600840.SH 的数据\n", + "成功获取 600842.SH 的数据\n", + "成功获取 600852.SH 的数据\n", + "成功获取 600856.SH 的数据\n", + "成功获取 600870.SH 的数据\n", + "成功获取 600878.SH 的数据\n", + "成功获取 600890.SH 的数据\n", + "成功获取 600891.SH 的数据\n", + "成功获取 600896.SH 的数据\n", + "成功获取 600899.SH 的数据\n", + "成功获取 600978.SH 的数据\n", + "成功获取 600991.SH 的数据\n", + "成功获取 601258.SH 的数据\n", + "成功获取 601268.SH 的数据\n", + "成功获取 601299.SH 的数据\n", + "成功获取 601558.SH 的数据\n", + "成功获取 603133.SH 的数据\n", + "成功获取 603157.SH 的数据\n", + "成功获取 603555.SH 的数据\n", + "成功获取 603603.SH 的数据\n", + "成功获取 603996.SH 的数据\n", + "成功获取 688086.SH 的数据\n", + "成功获取 688555.SH 的数据\n", + "成功获取 832317.BJ 的数据\n", + "成功获取 833874.BJ 的数据\n", + "成功获取 833994.BJ 的数据\n", + "成功获取 T00018.SH 的数据\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/tmp/ipykernel_964/3548322812.py:40: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " all_balancesheet = pd.concat(balancesheet_list, ignore_index=True)\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "所有日线数据已保存到 balancesheet.h5\n" ] } ], @@ -12906,7 +17380,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "id": "b27bb37b", "metadata": {}, "outputs": [ @@ -12914,18 +17388,18 @@ "name": "stdout", "output_type": "stream", "text": [ - "0 5.271746e+12\n", - "1 5.274428e+12\n", - "2 5.255519e+12\n", - "3 5.272164e+12\n", - "4 5.243822e+12\n", + "0 5.248834e+12\n", + "1 5.248834e+12\n", + "2 5.364899e+12\n", + "3 5.364899e+12\n", + "4 5.271746e+12\n", " ... \n", - "372450 1.150050e+09\n", - "372451 9.132874e+08\n", - "372452 4.395018e+08\n", - "372453 4.792661e+08\n", - "372454 3.738566e+08\n", - "Name: total_liab, Length: 372455, dtype: float64\n" + "381212 1.150050e+09\n", + "381213 9.132874e+08\n", + "381214 4.395018e+08\n", + "381215 4.792661e+08\n", + "381216 3.738566e+08\n", + "Name: total_liab, Length: 381217, dtype: float64\n" ] } ], diff --git a/main/train/Classify2_load_model.ipynb b/main/train/Classify2_load_model.ipynb index 2aedc8e..1c731c6 100644 --- a/main/train/Classify2_load_model.ipynb +++ b/main/train/Classify2_load_model.ipynb @@ -433,7 +433,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 11, "id": "85c3e3d0235ffffa", "metadata": { "ExecuteTime": { @@ -446,12 +446,12 @@ "fina_indicator_df = read_and_merge_h5_data('/mnt/d/PyProject/NewStock/data/fina_indicator.h5', key='fina_indicator',\n", " columns=['ts_code', 'ann_date', 'undist_profit_ps', 'ocfps', 'bps', 'roa', 'roe'],\n", " df=None)\n", - "# cashflow_df = read_and_merge_h5_data('/mnt/d/PyProject/NewStock/data/cashflow.h5', key='cashflow',\n", - "# columns=['ts_code', 'ann_date', 'n_cashflow_act'],\n", - "# df=None)\n", - "# balancesheet_df = read_and_merge_h5_data('/mnt/d/PyProject/NewStock/data/balancesheet.h5', key='balancesheet',\n", - "# columns=['ts_code', 'ann_date', 'money_cap', 'total_liab'],\n", - "# df=None)\n", + "cashflow_df = read_and_merge_h5_data('/mnt/d/PyProject/NewStock/data/cashflow.h5', key='cashflow',\n", + " columns=['ts_code', 'ann_date', 'n_cashflow_act'],\n", + " df=None)\n", + "balancesheet_df = read_and_merge_h5_data('/mnt/d/PyProject/NewStock/data/balancesheet.h5', key='balancesheet',\n", + " columns=['ts_code', 'ann_date', 'money_cap', 'total_liab'],\n", + " df=None)\n", "# top_list_df = read_and_merge_h5_data('/mnt/d/PyProject/NewStock/data/top_list.h5', key='top_list',\n", "# columns=['ts_code', 'trade_date', 'reason'],\n", "# df=None)\n", @@ -465,7 +465,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "id": "92d84ce15a562ec6", "metadata": { "ExecuteTime": { @@ -546,7 +546,140 @@ "df = add_financial_factor(df, fina_indicator_df, factor_value_col='roe')\n", "\n", "calculate_arbr(df, N=26)\n", - "df['log_circ_mv'] = np.log(df['circ_mv'])\n", + "df['log_circ_mv'] = np.log(df['circ_mv'])\n" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "da8d7a30", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "使用 'ann_date' 作为财务数据生效日期。\n", + "使用 'ann_date' 作为财务数据生效日期。\n", + "使用 'ann_date' 作为财务数据生效日期。\n", + "使用 'ann_date' 作为财务数据生效日期。\n", + "警告: 从 financial_data_subset 中移除了 15 行,因为其 'ts_code' 或 'ann_date' 列存在空值。\n", + "计算 BBI...\n", + "--- 计算日级别偏离度 (使用 pct_chg) ---\n", + "--- 计算日级别动量基准 (使用 pct_chg) ---\n", + "日级别动量基准计算完成 (使用 pct_chg)。\n", + "日级别偏离度计算完成 (使用 pct_chg)。\n", + "--- 计算日级别行业偏离度 (使用 pct_chg 和行业基准) ---\n", + "--- 计算日级别行业动量基准 (使用 pct_chg 和 cat_l2_code) ---\n", + "错误: 计算日级别行业动量基准需要以下列: ['pct_chg', 'cat_l2_code', 'trade_date', 'ts_code']。\n", + "错误: 计算日级别行业偏离度需要以下列: ['pct_chg', 'daily_industry_positive_benchmark', 'daily_industry_negative_benchmark']。请先运行 daily_industry_momentum_benchmark(df)。\n", + "Index(['ts_code', 'trade_date', 'open', 'close', 'high', 'low', 'vol',\n", + " 'amount', 'pct_chg', 'turnover_rate', 'pe_ttm', 'circ_mv', 'total_mv',\n", + " 'volume_ratio', 'is_st', 'up_limit', 'down_limit', 'buy_sm_vol',\n", + " 'sell_sm_vol', 'buy_lg_vol', 'sell_lg_vol', 'buy_elg_vol',\n", + " 'sell_elg_vol', 'net_mf_vol', 'his_low', 'his_high', 'cost_5pct',\n", + " 'cost_15pct', 'cost_50pct', 'cost_85pct', 'cost_95pct', 'weight_avg',\n", + " 'winner_rate', 'l2_code', 'undist_profit_ps', 'ocfps', 'roa', 'roe',\n", + " 'AR', 'BR', 'AR_BR', 'log_circ_mv', 'cashflow_to_ev_factor',\n", + " 'book_to_price_ratio', 'turnover_rate_mean_5', 'variance_20',\n", + " 'bbi_ratio_factor', 'daily_deviation', 'lg_elg_net_buy_vol',\n", + " 'flow_lg_elg_intensity', 'sm_net_buy_vol', 'flow_divergence_diff',\n", + " 'flow_divergence_ratio', 'total_buy_vol', 'lg_elg_buy_prop',\n", + " 'flow_struct_buy_change', 'lg_elg_net_buy_vol_change',\n", + " 'flow_lg_elg_accel', 'chip_concentration_range', 'chip_skewness',\n", + " 'floating_chip_proxy', 'cost_support_15pct_change',\n", + " 'cat_winner_price_zone', 'flow_chip_consistency',\n", + " 'profit_taking_vs_absorb', '_is_positive', '_is_negative',\n", + " 'cat_is_positive', '_pos_returns', '_neg_returns', '_pos_returns_sq',\n", + " '_neg_returns_sq', 'upside_vol', 'downside_vol', 'vol_ratio',\n", + " 'return_skew', 'return_kurtosis', 'volume_change_rate',\n", + " 'cat_volume_breakout', 'turnover_deviation', 'cat_turnover_spike',\n", + " 'avg_volume_ratio', 'cat_volume_ratio_breakout', 'vol_spike',\n", + " 'vol_std_5', 'atr_14', 'atr_6', 'obv'],\n", + " dtype='object')\n", + "Calculating lg_flow_mom_corr_20_60...\n", + "Finished lg_flow_mom_corr_20_60.\n", + "Calculating lg_flow_accel...\n", + "Finished lg_flow_accel.\n", + "Calculating profit_pressure...\n", + "Finished profit_pressure.\n", + "Calculating underwater_resistance...\n", + "Finished underwater_resistance.\n", + "Calculating cost_conc_std_20...\n", + "Finished cost_conc_std_20.\n", + "Calculating profit_decay_20...\n", + "Finished profit_decay_20.\n", + "Calculating vol_amp_loss_20...\n", + "Finished vol_amp_loss_20.\n", + "Calculating vol_drop_profit_cnt_5...\n", + "Finished vol_drop_profit_cnt_5.\n", + "Calculating lg_flow_vol_interact_20...\n", + "Finished lg_flow_vol_interact_20.\n", + "Calculating cost_break_confirm_cnt_5...\n", + "Finished cost_break_confirm_cnt_5.\n", + "Calculating atr_norm_channel_pos_14...\n", + "Finished atr_norm_channel_pos_14.\n", + "Calculating turnover_diff_skew_20...\n", + "Finished turnover_diff_skew_20.\n", + "Calculating lg_sm_flow_diverge_20...\n", + "Finished lg_sm_flow_diverge_20.\n", + "Calculating pullback_strong_20_20...\n", + "Finished pullback_strong_20_20.\n", + "Calculating vol_wgt_hist_pos_20...\n", + "Finished vol_wgt_hist_pos_20.\n", + "Calculating vol_adj_roc_20...\n", + "Finished vol_adj_roc_20.\n", + "Calculating cs_rank_net_lg_flow_val...\n", + "Finished cs_rank_net_lg_flow_val.\n", + "Calculating cs_rank_flow_divergence...\n", + "Finished cs_rank_flow_divergence.\n", + "Calculating cs_rank_ind_adj_lg_flow...\n", + "Finished cs_rank_ind_adj_lg_flow.\n", + "Calculating cs_rank_elg_buy_ratio...\n", + "Finished cs_rank_elg_buy_ratio.\n", + "Calculating cs_rank_rel_profit_margin...\n", + "Finished cs_rank_rel_profit_margin.\n", + "Calculating cs_rank_cost_breadth...\n", + "Finished cs_rank_cost_breadth.\n", + "Calculating cs_rank_dist_to_upper_cost...\n", + "Finished cs_rank_dist_to_upper_cost.\n", + "Calculating cs_rank_winner_rate...\n", + "Finished cs_rank_winner_rate.\n", + "Calculating cs_rank_intraday_range...\n", + "Finished cs_rank_intraday_range.\n", + "Calculating cs_rank_close_pos_in_range...\n", + "Finished cs_rank_close_pos_in_range.\n", + "Calculating cs_rank_opening_gap...\n", + "Error calculating cs_rank_opening_gap: Missing 'pre_close' column. Assigning NaN.\n", + "Calculating cs_rank_pos_in_hist_range...\n", + "Finished cs_rank_pos_in_hist_range.\n", + "Calculating cs_rank_vol_x_profit_margin...\n", + "Finished cs_rank_vol_x_profit_margin.\n", + "Calculating cs_rank_lg_flow_price_concordance...\n", + "Finished cs_rank_lg_flow_price_concordance.\n", + "Calculating cs_rank_turnover_per_winner...\n", + "Finished cs_rank_turnover_per_winner.\n", + "Calculating cs_rank_ind_cap_neutral_pe (Placeholder - requires statsmodels)...\n", + "Finished cs_rank_ind_cap_neutral_pe (Placeholder).\n", + "Calculating cs_rank_volume_ratio...\n", + "Finished cs_rank_volume_ratio.\n", + "Calculating cs_rank_elg_buy_sell_sm_ratio...\n", + "Finished cs_rank_elg_buy_sell_sm_ratio.\n", + "Calculating cs_rank_cost_dist_vol_ratio...\n", + "Finished cs_rank_cost_dist_vol_ratio.\n", + "Calculating cs_rank_size...\n", + "Finished cs_rank_size.\n", + "\n", + "RangeIndex: 5087384 entries, 0 to 5087383\n", + "Columns: 181 entries, ts_code to cs_rank_size\n", + "dtypes: bool(10), datetime64[ns](1), float64(165), int64(3), object(2)\n", + "memory usage: 6.5+ GB\n", + "None\n", + "['ts_code', 'trade_date', 'open', 'close', 'high', 'low', 'vol', 'amount', 'pct_chg', 'turnover_rate', 'pe_ttm', 'circ_mv', 'total_mv', 'volume_ratio', 'is_st', 'up_limit', 'down_limit', 'buy_sm_vol', 'sell_sm_vol', 'buy_lg_vol', 'sell_lg_vol', 'buy_elg_vol', 'sell_elg_vol', 'net_mf_vol', 'his_low', 'his_high', 'cost_5pct', 'cost_15pct', 'cost_50pct', 'cost_85pct', 'cost_95pct', 'weight_avg', 'winner_rate', 'cat_l2_code', 'undist_profit_ps', 'ocfps', 'roa', 'roe', 'AR', 'BR', 'AR_BR', 'log_circ_mv', 'cashflow_to_ev_factor', 'book_to_price_ratio', 'turnover_rate_mean_5', 'variance_20', 'bbi_ratio_factor', 'daily_deviation', 'lg_elg_net_buy_vol', 'flow_lg_elg_intensity', 'sm_net_buy_vol', 'flow_divergence_diff', 'flow_divergence_ratio', 'total_buy_vol', 'lg_elg_buy_prop', 'flow_struct_buy_change', 'lg_elg_net_buy_vol_change', 'flow_lg_elg_accel', 'chip_concentration_range', 'chip_skewness', 'floating_chip_proxy', 'cost_support_15pct_change', 'cat_winner_price_zone', 'flow_chip_consistency', 'profit_taking_vs_absorb', 'cat_is_positive', 'upside_vol', 'downside_vol', 'vol_ratio', 'return_skew', 'return_kurtosis', 'volume_change_rate', 'cat_volume_breakout', 'turnover_deviation', 'cat_turnover_spike', 'avg_volume_ratio', 'cat_volume_ratio_breakout', 'vol_spike', 'vol_std_5', 'atr_14', 'atr_6', 'obv', 'maobv_6', 'rsi_3', 'return_5', 'return_20', 'std_return_5', 'std_return_90', 'std_return_90_2', 'act_factor1', 'act_factor2', 'act_factor3', 'act_factor4', 'rank_act_factor1', 'rank_act_factor2', 'rank_act_factor3', 'cov', 'delta_cov', 'alpha_22_improved', 'alpha_003', 'alpha_007', 'alpha_013', 'vol_break', 'weight_roc5', 'price_cost_divergence', 'smallcap_concentration', 'cost_stability', 'high_cost_break_days', 'liquidity_risk', 'turnover_std', 'mv_volatility', 'volume_growth', 'mv_growth', 'momentum_factor', 'resonance_factor', 'log_close', 'cat_vol_spike', 'up', 'down', 'obv_maobv_6', 'std_return_5_over_std_return_90', 'std_return_90_minus_std_return_90_2', 'cat_af2', 'cat_af3', 'cat_af4', 'act_factor5', 'act_factor6', 'active_buy_volume_large', 'active_buy_volume_big', 'active_buy_volume_small', 'buy_lg_vol_minus_sell_lg_vol', 'buy_elg_vol_minus_sell_elg_vol', 'ctrl_strength', 'low_cost_dev', 'asymmetry', 'lock_factor', 'cat_vol_break', 'cost_atr_adj', 'cat_golden_resonance', 'mv_turnover_ratio', 'mv_adjusted_volume', 'mv_weighted_turnover', 'nonlinear_mv_volume', 'mv_volume_ratio', 'mv_momentum', 'lg_flow_mom_corr_20_60', 'lg_flow_accel', 'profit_pressure', 'underwater_resistance', 'cost_conc_std_20', 'profit_decay_20', 'vol_amp_loss_20', 'vol_drop_profit_cnt_5', 'lg_flow_vol_interact_20', 'cost_break_confirm_cnt_5', 'atr_norm_channel_pos_14', 'turnover_diff_skew_20', 'lg_sm_flow_diverge_20', 'pullback_strong_20_20', 'vol_wgt_hist_pos_20', 'vol_adj_roc_20', 'cs_rank_net_lg_flow_val', 'cs_rank_flow_divergence', 'cs_rank_ind_adj_lg_flow', 'cs_rank_elg_buy_ratio', 'cs_rank_rel_profit_margin', 'cs_rank_cost_breadth', 'cs_rank_dist_to_upper_cost', 'cs_rank_winner_rate', 'cs_rank_intraday_range', 'cs_rank_close_pos_in_range', 'cs_rank_opening_gap', 'cs_rank_pos_in_hist_range', 'cs_rank_vol_x_profit_margin', 'cs_rank_lg_flow_price_concordance', 'cs_rank_turnover_per_winner', 'cs_rank_ind_cap_neutral_pe', 'cs_rank_volume_ratio', 'cs_rank_elg_buy_sell_sm_ratio', 'cs_rank_cost_dist_vol_ratio', 'cs_rank_size']\n" + ] + } + ], + "source": [ "df = calculate_cashflow_to_ev_factor(df, cashflow_df, balancesheet_df)\n", "df = caculate_book_to_price_ratio(df, fina_indicator_df)\n", "\n", @@ -608,7 +741,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 13, "id": "b87b938028afa206", "metadata": { "ExecuteTime": { @@ -646,7 +779,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 14, "id": "f4f16d63ad18d1bc", "metadata": { "ExecuteTime": { @@ -872,7 +1005,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 15, "id": "40e6b68a91b30c79", "metadata": { "ExecuteTime": { @@ -1192,7 +1325,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 16, "id": "47c12bb34062ae7a", "metadata": { "ExecuteTime": { @@ -1226,7 +1359,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 17, "id": "29221dde", "metadata": {}, "outputs": [ @@ -1269,7 +1402,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 18, "id": "03ee5daf", "metadata": {}, "outputs": [], @@ -1282,7 +1415,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 19, "id": "b76ea08a", "metadata": {}, "outputs": [ @@ -1303,7 +1436,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "MAD Filtering: 100%|██████████| 131/131 [00:13<00:00, 9.90it/s]\n" + "MAD Filtering: 100%|██████████| 131/131 [00:15<00:00, 8.70it/s]\n" ] }, { @@ -1318,7 +1451,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "MAD Filtering: 100%|██████████| 131/131 [00:14<00:00, 8.90it/s]\n" + "MAD Filtering: 100%|██████████| 131/131 [00:15<00:00, 8.47it/s]\n" ] }, { @@ -1500,7 +1633,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 20, "id": "3ff2d1c5", "metadata": {}, "outputs": [], @@ -1641,17 +1774,17 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 21, "id": "a5bbb8be", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "" + "" ] }, - "execution_count": 19, + "execution_count": 21, "metadata": {}, "output_type": "execute_result" } @@ -1666,7 +1799,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 25, "id": "5d1522a7538db91b", "metadata": { "ExecuteTime": { @@ -1705,7 +1838,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 26, "id": "09b1799e", "metadata": {}, "outputs": [ @@ -1727,7 +1860,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 27, "id": "e53b209a", "metadata": {}, "outputs": [ @@ -1775,7 +1908,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.13.2" + "version": "3.12.11" } }, "nbformat": 4, diff --git a/qmt/__init__.py b/qmt/__init__.py index e69de29..14b4093 100644 --- a/qmt/__init__.py +++ b/qmt/__init__.py @@ -0,0 +1,20 @@ +# coding: utf-8 +""" +QMT (Quantitative Trading) Module + +提供量化交易相关的功能: +- Redis Stream 消息处理 +- 交易信号发送 +- 回测消息消费 +- 细粒度日志记录 +""" + +from .message_processor import StreamMessageProcessor, send_qmt_signal_to_stream +from .logger import QMTLogger, get_qmt_logger + +__all__ = [ + "StreamMessageProcessor", + "send_qmt_signal_to_stream", + "QMTLogger", + "get_qmt_logger", +] diff --git a/qmt/backtest_consumer.py b/qmt/backtest_consumer.py new file mode 100644 index 0000000..119d6ed --- /dev/null +++ b/qmt/backtest_consumer.py @@ -0,0 +1,440 @@ +# coding: utf-8 +""" +QMT 回测消息消费者 + +独立的回测消息消费脚本,用于: +- 消费回测消息流 +- 记录完整的处理流程日志 +- 模拟订单执行(不执行真实交易) +- ACK 确认消息 + +使用方法: + # 守护模式(持续运行,处理所有配置的策略) + python backtest_consumer.py + + # 单次运行模式(处理一次后退出) + python backtest_consumer.py --once + + # 指定策略运行 + python backtest_consumer.py --strategy StrategyA + python backtest_consumer.py --once --strategy StrategyA,StrategyB + +配置说明: + 可通过环境变量或 .env.local 文件配置: + - REDIS_HOST: Redis 主机地址(默认: localhost) + - REDIS_PORT: Redis 端口(默认: 6379) + - REDIS_PASSWORD: Redis 密码(默认: None) + - REDIS_DB: Redis 数据库(默认: 0) + - BACKTEST_CONSUMER_ID: 消费者ID(默认: backtest-consumer-1) + - BACKTEST_STRATEGIES: 默认策略列表,逗号分隔 + - LOG_LEVEL: 日志级别(默认: DEBUG) + - LOG_FILE: 日志文件路径(默认: logs/backtest_consumer.log) + +消息格式: + 消费的消息为 JSON 格式,包含以下字段: + - strategy_name: 策略名称 + - stock_code: 股票代码(如 000001.SZ) + - action: 交易动作(BUY/SELL) + - price: 价格 + - total_slots: 目标持仓槽位数 + - timestamp: 时间戳 + - is_backtest: 是否为回测模式 +""" + +import os +import sys +import time +import json +import signal +import argparse +from datetime import datetime +from typing import List, Optional, Dict, Any + +# 添加父目录到路径 +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) + +try: + from message_processor import StreamMessageProcessor + from logger import QMTLogger +except ImportError as e: + print(f"导入错误: {e}") + print("请确保在 qmt 目录下运行此脚本") + sys.exit(1) + + +def load_config() -> Dict[str, Any]: + """加载配置文件 + + 从 /qmt/config/.env.local 加载环境变量配置 + + Returns: + 配置字典 + """ + # 尝试加载 python-dotenv + dotenv_loaded = False + try: + from dotenv import load_dotenv + dotenv_available = True + except ImportError: + dotenv_available = False + print("[Config] 警告: 未安装 python-dotenv,使用默认配置") + + # 如果 dotenv 可用,尝试加载配置文件 + if dotenv_available: + # 尝试多个路径 + env_paths = [ + os.path.join( + os.path.dirname(os.path.abspath(__file__)), "config", ".env.local" + ), + os.path.join(os.path.dirname(__file__), "config", ".env.local"), + os.path.join(os.path.dirname(__file__), "..", "config", ".env.local"), + "/qmt/config/.env.local", + "config/.env.local", + ] + + for env_path in env_paths: + if os.path.exists(env_path): + load_dotenv(env_path) + print(f"[Config] 加载配置文件: {env_path}") + dotenv_loaded = True + break + + if not dotenv_loaded: + print("[Config] 警告: 未找到 .env.local 文件,使用默认配置") + + + # 从环境变量读取配置 + config = { + "redis": { + "host": os.getenv("REDIS_HOST", "localhost"), + "port": int(os.getenv("REDIS_PORT", "6379")), + "password": os.getenv("REDIS_PASSWORD") or None, + "db": int(os.getenv("REDIS_DB", "0")), + }, + "consumer_id": os.getenv("BACKTEST_CONSUMER_ID", "backtest-consumer-1"), + "block_timeout": int(os.getenv("BACKTEST_BLOCK_TIMEOUT", "5000")), + "strategies": os.getenv("BACKTEST_STRATEGIES", ""), + "simulate_delay": float(os.getenv("BACKTEST_SIMULATE_DELAY", "0.1")), + "log_level": os.getenv("LOG_LEVEL", "DEBUG"), + "log_file": os.getenv("LOG_FILE", "logs/backtest_consumer.log"), + } + + # 解析策略列表 + if config["strategies"]: + config["strategy_list"] = [ + s.strip() for s in config["strategies"].split(",") if s.strip() + ] + else: + config["strategy_list"] = [] + + return config + + +class BacktestConsumer: + """回测消息消费者""" + + def __init__(self, config: Dict[str, Any]): + """初始化回测消费者 + + Args: + config: 配置字典 + """ + self.config = config + self.logger = QMTLogger(name="BacktestConsumer", log_file=config["log_file"]) + + # 初始化 Stream 处理器 + self.processor = StreamMessageProcessor(redis_config=config["redis"]) + + # 运行状态 + self.running = True + + # 统计信息 + self.stats = { + "total_received": 0, + "total_processed": 0, + "total_failed": 0, + "start_time": datetime.now(), + } + + self.logger.info(f"[BacktestConsumer] 初始化完成") + self.logger.info(f"[BacktestConsumer] 消费者ID: {config['consumer_id']}") + self.logger.info( + f"[BacktestConsumer] 策略列表: {config['strategy_list'] or '所有策略'}" + ) + + def signal_handler(self, signum, frame): + """信号处理函数""" + self.logger.info(f"[BacktestConsumer] 收到信号 {signum},准备退出...") + self.running = False + + def simulate_order(self, strategy_name: str, data: Dict[str, Any]) -> bool: + """模拟订单执行 + + Args: + strategy_name: 策略名称 + data: 消息数据 + + Returns: + 模拟成功返回 True + """ + action = data.get("action") + stock_code = data.get("stock_code") + price = data.get("price", 0) + total_slots = data.get("total_slots", 0) + + self.logger.log_order_execution( + strategy_name=strategy_name, + stock_code=stock_code, + action=action, + volume=100, # 模拟数量 + price=price, + ) + + # 模拟延迟 + if self.config["simulate_delay"] > 0: + time.sleep(self.config["simulate_delay"]) + + # 记录模拟结果 + if action == "BUY": + self.logger.info( + f"[模拟交易] {strategy_name} 买入 {stock_code} @ {price}, " + f"目标持仓: {total_slots}只" + ) + elif action == "SELL": + self.logger.info( + f"[模拟交易] {strategy_name} 卖出 {stock_code} @ {price}, 清仓释放槽位" + ) + else: + self.logger.warning(f"[模拟交易] 未知动作: {action}") + return False + + # 记录成功 + self.logger.log_order_execution( + strategy_name=strategy_name, + stock_code=stock_code, + action=action, + volume=100, + price=price, + order_id=-1, # 模拟订单ID + ) + + return True + + def process_messages(self, strategy_name: str) -> int: + """处理单个策略的消息 + + Args: + strategy_name: 策略名称 + + Returns: + 处理的消息数量 + """ + processed = 0 + + try: + # 消费消息(回测模式,不使用消费者组) + messages = self.processor.consume_message( + strategy_name=strategy_name, + consumer_id=self.config["consumer_id"], + is_backtest=True, + block_ms=100, # 短阻塞 + count=10, # 每次最多处理10条 + ) + + if not messages: + return 0 + + for msg_id, data in messages: + self.stats["total_received"] += 1 + + try: + stream_key = f"qmt:{strategy_name}:backtest" + + # 1. 记录消息接收 + self.logger.log_message_receive(stream_key, msg_id, data) + + # 2. 记录消息解析 + self.logger.log_message_parse( + strategy_name=data.get("strategy_name", strategy_name), + stock_code=data.get("stock_code", ""), + action=data.get("action", ""), + price=data.get("price", 0), + extra_fields={ + "total_slots": data.get("total_slots"), + "timestamp": data.get("timestamp"), + "is_backtest": data.get("is_backtest"), + }, + ) + + # 3. 业务校验 + self.logger.log_validation( + validation_type="field_check", + strategy_name=strategy_name, + details={"fields": list(data.keys())}, + result=True, + ) + + # 4. 模拟订单执行 + success = self.simulate_order(strategy_name, data) + + if success: + self.stats["total_processed"] += 1 + else: + self.stats["total_failed"] += 1 + + # 5. ACK 消息(回测模式不需要真正的 ACK,但记录日志) + self.logger.log_ack(stream_key, msg_id, True) + + processed += 1 + + except Exception as e: + error_msg = f"消息处理异常: {str(e)}" + self.logger.error(error_msg, exc_info=True) + self.logger.log_failure( + stream_key=f"qmt:{strategy_name}:backtest", + message_id=msg_id, + error_reason=str(e), + to_failure_queue=False, + ) + self.stats["total_failed"] += 1 + + except Exception as e: + self.logger.error(f"消费消息异常: {str(e)}", exc_info=True) + + return processed + + def run_once(self, specific_strategies: Optional[List[str]] = None) -> None: + """单次运行 + + Args: + specific_strategies: 指定要处理的策略列表,None 则处理所有 + """ + strategies = specific_strategies or self.config["strategy_list"] + + if not strategies: + self.logger.warning("[BacktestConsumer] 未指定策略,退出") + return + + self.logger.info(f"[BacktestConsumer] 单次运行,策略: {strategies}") + + total_processed = 0 + for strategy in strategies: + count = self.process_messages(strategy) + total_processed += count + if count > 0: + self.logger.info( + f"[BacktestConsumer] 策略 {strategy} 处理 {count} 条消息" + ) + + self.logger.info( + f"[BacktestConsumer] 单次运行完成,共处理 {total_processed} 条消息" + ) + self._log_stats() + + def run_daemon(self, specific_strategies: Optional[List[str]] = None) -> None: + """守护模式运行 + + Args: + specific_strategies: 指定要处理的策略列表,None 则处理所有 + """ + strategies = specific_strategies or self.config["strategy_list"] + + if not strategies: + self.logger.warning("[BacktestConsumer] 未指定策略,退出") + return + + self.logger.info(f"[BacktestConsumer] 守护模式启动,策略: {strategies}") + self.logger.info("按 Ctrl+C 停止") + + # 设置信号处理 + signal.signal(signal.SIGINT, self.signal_handler) + signal.signal(signal.SIGTERM, self.signal_handler) + + last_heartbeat = time.time() + + while self.running: + try: + # 处理所有策略 + for strategy in strategies: + if not self.running: + break + self.process_messages(strategy) + + # 心跳日志(每60秒) + if time.time() - last_heartbeat > 60: + self.logger.log_heartbeat( + component="BacktestConsumer", + status="running", + extra_info=self.stats, + ) + last_heartbeat = time.time() + + # 短暂休眠,避免CPU占用过高 + time.sleep(0.1) + + except Exception as e: + self.logger.error(f"守护循环异常: {str(e)}", exc_info=True) + time.sleep(1) + + self.logger.info("[BacktestConsumer] 守护模式停止") + self._log_stats() + + def _log_stats(self) -> None: + """记录统计信息""" + runtime = (datetime.now() - self.stats["start_time"]).total_seconds() + self.logger.info("=" * 50) + self.logger.info("[统计信息]") + self.logger.info(f"运行时间: {runtime:.1f} 秒") + self.logger.info(f"接收消息: {self.stats['total_received']}") + self.logger.info(f"处理成功: {self.stats['total_processed']}") + self.logger.info(f"处理失败: {self.stats['total_failed']}") + self.logger.info("=" * 50) + + +def main(): + """主函数""" + parser = argparse.ArgumentParser( + description="QMT 回测消息消费者", + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=""" +使用示例: + python backtest_consumer.py # 守护模式,处理所有配置的策略 + python backtest_consumer.py --once # 单次运行 + python backtest_consumer.py --strategy A,B # 指定策略 + python backtest_consumer.py --once --strategy A # 单次运行指定策略 + """, + ) + + parser.add_argument( + "--once", action="store_true", help="单次运行模式(处理一次后退出)" + ) + + parser.add_argument( + "--strategy", + type=str, + default="", + help="指定策略名称,多个用逗号分隔(如: StrategyA,StrategyB)", + ) + + args = parser.parse_args() + + # 加载配置 + config = load_config() + + # 命令行参数覆盖配置 + specific_strategies = None + if args.strategy: + specific_strategies = [s.strip() for s in args.strategy.split(",") if s.strip()] + + # 创建消费者 + consumer = BacktestConsumer(config) + + # 运行 + if args.once: + consumer.run_once(specific_strategies) + else: + consumer.run_daemon(specific_strategies) + + +if __name__ == "__main__": + main() diff --git a/qmt/logger.py b/qmt/logger.py new file mode 100644 index 0000000..b8f253e --- /dev/null +++ b/qmt/logger.py @@ -0,0 +1,301 @@ +# coding: utf-8 +""" +QMT Fine-grained Logger Module + +提供细粒度的日志记录功能,用于追踪消息处理全流程。 +所有方法默认使用 DEBUG 级别,确保详细的追踪信息。 +""" + +import logging +import sys +import os +from logging.handlers import RotatingFileHandler +from typing import Dict, Any, Optional + + +class QMTLogger: + """QMT 细粒度日志记录器 + + 提供消息处理全流程的日志记录,包括: + - 消息接收 + - 消息解析 + - 业务校验 + - 订单执行 + - 消息确认 + - 失败处理 + """ + + def __init__( + self, + name: str = "QMT_Stream", + log_file: str = "logs/qmt_stream.log", + log_level: int = logging.DEBUG, + ): + """初始化日志记录器 + + Args: + name: 日志记录器名称 + log_file: 日志文件路径 + log_level: 日志级别 + """ + self.logger = logging.getLogger(name) + self.logger.setLevel(log_level) + + # 避免重复添加处理器 + if self.logger.handlers: + return + + # 创建日志目录 + log_dir = os.path.dirname(log_file) + if log_dir and not os.path.exists(log_dir): + os.makedirs(log_dir) + + # 日志格式 + formatter = logging.Formatter( + "[%(asctime)s] [%(levelname)s] [%(filename)s:%(lineno)d] [%(threadName)s] %(message)s", + datefmt="%Y-%m-%d %H:%M:%S", + ) + + # 文件处理器 (轮转,最大 10MB,保留 5 个备份) + file_handler = RotatingFileHandler( + log_file, + maxBytes=10 * 1024 * 1024, # 10MB + backupCount=5, + encoding="utf-8", + ) + file_handler.setFormatter(formatter) + file_handler.setLevel(log_level) + + # 控制台处理器 + console_handler = logging.StreamHandler(sys.stdout) + console_handler.setFormatter(formatter) + console_handler.setLevel(log_level) + + self.logger.addHandler(file_handler) + self.logger.addHandler(console_handler) + + self.logger.debug(f"[QMTLogger] 日志记录器初始化完成: {name}") + + def log_message_receive( + self, stream_key: str, message_id: str, message_data: Dict[str, Any] + ) -> None: + """记录消息接收日志 + + Args: + stream_key: 流键名 + message_id: 消息ID + message_data: 消息数据 + """ + self.logger.debug( + f"[消息接收] stream={stream_key}, id={message_id}, " + f"data={str(message_data)[:500]}" + ) + + def log_message_parse( + self, + strategy_name: str, + stock_code: str, + action: str, + price: float, + extra_fields: Optional[Dict[str, Any]] = None, + ) -> None: + """记录消息解析日志 + + Args: + strategy_name: 策略名称 + stock_code: 股票代码 + action: 交易动作 + price: 价格 + extra_fields: 其他字段 + """ + extra_str = f", extra={extra_fields}" if extra_fields else "" + self.logger.debug( + f"[消息解析] strategy={strategy_name}, code={stock_code}, " + f"action={action}, price={price}{extra_str}" + ) + + def log_validation( + self, + validation_type: str, + strategy_name: str, + details: Dict[str, Any], + result: bool, + ) -> None: + """记录业务校验日志 + + Args: + validation_type: 校验类型 (如: slot_check, date_check, field_check) + strategy_name: 策略名称 + details: 校验详情 + result: 校验结果 (True/False) + """ + result_str = "通过" if result else "拦截" + self.logger.debug( + f"[业务校验] type={validation_type}, strategy={strategy_name}, " + f"result={result_str}, details={details}" + ) + + def log_order_execution( + self, + strategy_name: str, + stock_code: str, + action: str, + volume: int, + price: float, + order_id: Optional[int] = None, + error: Optional[str] = None, + ) -> None: + """记录订单执行日志 + + Args: + strategy_name: 策略名称 + stock_code: 股票代码 + action: 交易动作 + volume: 数量 + price: 价格 + order_id: 订单ID (成功时) + error: 错误信息 (失败时) + """ + if error: + self.logger.error( + f"[订单执行失败] strategy={strategy_name}, code={stock_code}, " + f"action={action}, vol={volume}, price={price}, error={error}" + ) + elif order_id is not None: + self.logger.info( + f"[订单执行成功] strategy={strategy_name}, code={stock_code}, " + f"action={action}, vol={volume}, price={price}, order_id={order_id}" + ) + else: + self.logger.debug( + f"[订单执行请求] strategy={strategy_name}, code={stock_code}, " + f"action={action}, vol={volume}, price={price}" + ) + + def log_ack(self, stream_key: str, message_id: str, success: bool) -> None: + """记录消息确认日志 + + Args: + stream_key: 流键名 + message_id: 消息ID + success: 确认是否成功 + """ + result_str = "成功" if success else "失败" + if success: + self.logger.debug( + f"[消息确认] stream={stream_key}, id={message_id}, result={result_str}" + ) + else: + self.logger.warning( + f"[消息确认] stream={stream_key}, id={message_id}, result={result_str}" + ) + + def log_failure( + self, + stream_key: str, + message_id: str, + error_reason: str, + to_failure_queue: bool = True, + ) -> None: + """记录失败处理日志 + + Args: + stream_key: 流键名 + message_id: 消息ID + error_reason: 失败原因 + to_failure_queue: 是否已进入失败队列 + """ + queue_str = "已入失败队列" if to_failure_queue else "未入失败队列" + self.logger.warning( + f"[失败处理] stream={stream_key}, id={message_id}, " + f"reason={error_reason}, status={queue_str}" + ) + + def log_consumer_group( + self, stream_key: str, group_name: str, action: str, result: bool + ) -> None: + """记录消费者组操作日志 + + Args: + stream_key: 流键名 + group_name: 消费者组名 + action: 操作 (create, check) + result: 操作结果 + """ + result_str = "成功" if result else "失败" + self.logger.debug( + f"[消费者组] stream={stream_key}, group={group_name}, " + f"action={action}, result={result_str}" + ) + + def log_pending_claim( + self, stream_key: str, consumer_id: str, message_ids: list, count: int + ) -> None: + """记录待处理消息认领日志 + + Args: + stream_key: 流键名 + consumer_id: 消费者ID + message_ids: 认领的消息ID列表 + count: 认领数量 + """ + self.logger.info( + f"[消息认领] stream={stream_key}, consumer={consumer_id}, " + f"claimed_count={count}, ids={message_ids}" + ) + + def log_heartbeat( + self, component: str, status: str, extra_info: Optional[Dict[str, Any]] = None + ) -> None: + """记录心跳日志 + + Args: + component: 组件名称 + status: 状态 + extra_info: 额外信息 + """ + extra_str = f", info={extra_info}" if extra_info else "" + self.logger.debug(f"[心跳] component={component}, status={status}{extra_str}") + + def info(self, message: str) -> None: + """记录 INFO 级别日志""" + self.logger.info(message) + + def warning(self, message: str) -> None: + """记录 WARNING 级别日志""" + self.logger.warning(message) + + def error(self, message: str, exc_info: bool = False) -> None: + """记录 ERROR 级别日志""" + self.logger.error(message, exc_info=exc_info) + + def debug(self, message: str) -> None: + """记录 DEBUG 级别日志""" + self.logger.debug(message) + + +# 全局日志记录器实例 +_default_logger = None + + +def get_qmt_logger( + name: str = "QMT_Stream", + log_file: str = "logs/qmt_stream.log", + log_level: int = logging.DEBUG, +) -> QMTLogger: + """获取 QMT 日志记录器实例 + + 返回单例模式的日志记录器。 + + Args: + name: 日志记录器名称 + log_file: 日志文件路径 + log_level: 日志级别 + + Returns: + QMTLogger 实例 + """ + global _default_logger + if _default_logger is None: + _default_logger = QMTLogger(name, log_file, log_level) + return _default_logger diff --git a/qmt/message_processor.py b/qmt/message_processor.py new file mode 100644 index 0000000..f1d877d --- /dev/null +++ b/qmt/message_processor.py @@ -0,0 +1,533 @@ +# coding: utf-8 +""" +QMT Redis Stream Message Processor + +统一封装 Redis Stream 操作,提供消息发送、消费、确认、失败处理等功能。 +""" + +import json +import logging +import socket +import os +from typing import Dict, Any, Optional, List, Tuple +from datetime import datetime + +import redis + + +class StreamMessageProcessor: + """Redis Stream 消息处理器 + + 封装所有 Redis Stream 操作,包括: + - 消息发送 (XADD) + - 消息消费 (XREADGROUP) + - 消息确认 (XACK) + - 失败队列 (XADD to failure stream) + - 消费者组管理 + - 待处理消息认领 + """ + + # 消费者组名称 + CONSUMER_GROUP = "qmt_consumers" + # 最大消息长度 + MAXLEN = 1000 + # 流键前缀 + STREAM_PREFIX = "qmt" + + def __init__( + self, + redis_client: Optional[redis.Redis] = None, + redis_config: Optional[Dict[str, Any]] = None, + ): + """初始化消息处理器 + + Args: + redis_client: 已有的 Redis 连接实例 + redis_config: Redis 配置字典 (当 redis_client 为 None 时使用) + 格式: {"host": "localhost", "port": 6379, "password": None, "db": 0} + """ + self.logger = logging.getLogger("QMT_Stream") + + if redis_client: + self.r = redis_client + elif redis_config: + self.r = redis.Redis( + host=redis_config.get("host", "localhost"), + port=redis_config.get("port", 6379), + password=redis_config.get("password"), + db=redis_config.get("db", 0), + decode_responses=True, + ) + else: + # 尝试从环境变量加载配置 + self.r = self._load_redis_from_env() + + self.logger.debug(f"[StreamMessageProcessor] Redis连接初始化完成") + + def _load_redis_from_env(self) -> redis.Redis: + """从环境变量加载 Redis 配置""" + import os + + host = os.getenv("REDIS_HOST", "localhost") + port = int(os.getenv("REDIS_PORT", "6379")) + password = os.getenv("REDIS_PASSWORD") or None + db = int(os.getenv("REDIS_DB", "0")) + + return redis.Redis( + host=host, port=port, password=password, db=db, decode_responses=True + ) + + def _get_stream_key(self, strategy_name: str, is_backtest: bool = False) -> str: + """获取流键名 + + Args: + strategy_name: 策略名称 + is_backtest: 是否为回测模式 + + Returns: + 流键名,格式: qmt:{strategy_name}:real 或 qmt:{strategy_name}:backtest + """ + suffix = "backtest" if is_backtest else "real" + return f"{self.STREAM_PREFIX}:{strategy_name}:{suffix}" + + def _get_failure_stream_key(self, strategy_name: str) -> str: + """获取失败流键名 + + Args: + strategy_name: 策略名称 + + Returns: + 失败流键名,格式: qmt:{strategy_name}:failed + """ + return f"{self.STREAM_PREFIX}:{strategy_name}:failed" + + def send_message( + self, + strategy_name: str, + message_data: Dict[str, Any], + is_backtest: bool = False, + ) -> Optional[str]: + """发送消息到 Redis Stream + + Args: + strategy_name: 策略名称 + message_data: 消息数据字典 + is_backtest: 是否为回测消息 + + Returns: + 消息ID (格式: timestamp-sequence),失败返回 None + """ + stream_key = self._get_stream_key(strategy_name, is_backtest) + + try: + # 确保消息数据是字符串格式 + if isinstance(message_data, dict): + message_json = json.dumps(message_data, ensure_ascii=False) + else: + message_json = str(message_data) + + # 使用 XADD 发送消息,设置最大长度 + message_id = self.r.xadd( + stream_key, + {"data": message_json}, + maxlen=self.MAXLEN, + approximate=True, # 使用近似裁剪,提高性能 + ) + + self.logger.debug( + f"[消息发送] stream={stream_key}, id={message_id}, " + f"is_backtest={is_backtest}, data={message_json[:200]}" + ) + + return message_id + + except redis.RedisError as e: + self.logger.error(f"[消息发送失败] stream={stream_key}, error={str(e)}") + return None + except Exception as e: + self.logger.error( + f"[消息发送异常] stream={stream_key}, error={str(e)}", exc_info=True + ) + return None + + def create_consumer_group( + self, strategy_name: str, is_backtest: bool = False + ) -> bool: + """创建消费者组 + + 如果消费者组已存在,则忽略错误。 + + Args: + strategy_name: 策略名称 + is_backtest: 是否为回测模式 + + Returns: + 创建成功返回 True,失败返回 False + """ + # 回测模式不使用消费者组 + if is_backtest: + return True + + stream_key = self._get_stream_key(strategy_name, is_backtest) + + try: + # 创建消费者组,从最新消息开始消费 ($) + self.r.xgroup_create(stream_key, self.CONSUMER_GROUP, id="$", mkstream=True) + self.logger.info( + f"[消费者组创建] stream={stream_key}, group={self.CONSUMER_GROUP}" + ) + return True + + except redis.ResponseError as e: + if "BUSYGROUP" in str(e): + # 消费者组已存在,这是正常的 + self.logger.debug( + f"[消费者组已存在] stream={stream_key}, group={self.CONSUMER_GROUP}" + ) + return True + else: + self.logger.error( + f"[消费者组创建失败] stream={stream_key}, error={str(e)}" + ) + return False + except Exception as e: + self.logger.error( + f"[消费者组创建异常] stream={stream_key}, error={str(e)}", exc_info=True + ) + return False + + def consume_message( + self, + strategy_name: str, + consumer_id: Optional[str] = None, + is_backtest: bool = False, + block_ms: int = 5000, + count: int = 1, + ) -> Optional[List[Tuple[str, Dict[str, Any]]]]: + """从 Redis Stream 消费消息 + + Args: + strategy_name: 策略名称 + consumer_id: 消费者ID,None 则自动生成 + is_backtest: 是否为回测模式 + block_ms: 阻塞等待时间(毫秒) + count: 每次消费的消息数量 + + Returns: + 消息列表,每个元素为 (message_id, message_data) 元组 + 无消息或失败返回 None + """ + stream_key = self._get_stream_key(strategy_name, is_backtest) + + # 生成消费者ID + if consumer_id is None: + consumer_id = self._generate_consumer_id() + + try: + if is_backtest: + # 回测模式使用 XREAD (不使用消费者组) + messages = self.r.xread( + {stream_key: "0"}, # 从最早未确认消息开始 + count=count, + block=block_ms, + ) + else: + # 实盘模式使用 XREADGROUP + # 确保消费者组存在 + self.create_consumer_group(strategy_name, is_backtest) + + messages = self.r.xreadgroup( + groupname=self.CONSUMER_GROUP, + consumername=consumer_id, + streams={stream_key: ">"}, # 读取新消息 + count=count, + block=block_ms, + ) + + if not messages: + return None + + # 解析消息 + result = [] + for stream_name, stream_messages in messages: + for msg_id, msg_fields in stream_messages: + # 解析消息数据 + data = msg_fields.get("data", "{}") + try: + parsed_data = json.loads(data) + except json.JSONDecodeError: + parsed_data = {"raw_data": data} + + result.append((msg_id, parsed_data)) + + self.logger.debug( + f"[消息接收] stream={stream_key}, id={msg_id}, " + f"consumer={consumer_id}, data={str(parsed_data)[:200]}" + ) + + return result if result else None + + except redis.RedisError as e: + self.logger.error(f"[消息消费失败] stream={stream_key}, error={str(e)}") + return None + except Exception as e: + self.logger.error( + f"[消息消费异常] stream={stream_key}, error={str(e)}", exc_info=True + ) + return None + + def ack_message( + self, strategy_name: str, message_id: str, is_backtest: bool = False + ) -> bool: + """确认消息已消费 + + Args: + strategy_name: 策略名称 + message_id: 消息ID + is_backtest: 是否为回测模式 + + Returns: + 确认成功返回 True,失败返回 False + """ + # 回测模式不需要确认 + if is_backtest: + return True + + stream_key = self._get_stream_key(strategy_name, is_backtest) + + try: + result = self.r.xack(stream_key, self.CONSUMER_GROUP, message_id) + + if result == 1: + self.logger.debug( + f"[消息确认] stream={stream_key}, id={message_id}, success=True" + ) + return True + else: + self.logger.warning( + f"[消息确认] stream={stream_key}, id={message_id}, success=False, result={result}" + ) + return False + + except redis.RedisError as e: + self.logger.error( + f"[消息确认失败] stream={stream_key}, id={message_id}, error={str(e)}" + ) + return False + except Exception as e: + self.logger.error( + f"[消息确认异常] stream={stream_key}, id={message_id}, error={str(e)}", + exc_info=True, + ) + return False + + def send_to_failure_queue( + self, + strategy_name: str, + original_message: Dict[str, Any], + error_reason: str, + retry_count: int = 0, + ) -> Optional[str]: + """将失败消息发送到失败队列 + + Args: + strategy_name: 策略名称 + original_message: 原始消息数据 + error_reason: 失败原因 + retry_count: 重试次数 + + Returns: + 失败消息ID,失败返回 None + """ + failure_key = self._get_failure_stream_key(strategy_name) + + try: + failure_data = { + "original_message": json.dumps(original_message, ensure_ascii=False), + "error_reason": error_reason, + "failed_at": datetime.now().isoformat(), + "retry_count": str(retry_count), + } + + message_id = self.r.xadd(failure_key, failure_data) + + self.logger.warning( + f"[失败队列] strategy={strategy_name}, id={message_id}, " + f"reason={error_reason}, retry_count={retry_count}" + ) + + return message_id + + except redis.RedisError as e: + self.logger.error( + f"[失败队列发送失败] strategy={strategy_name}, error={str(e)}" + ) + return None + except Exception as e: + self.logger.error( + f"[失败队列发送异常] strategy={strategy_name}, error={str(e)}", + exc_info=True, + ) + return None + + def claim_pending_messages( + self, + strategy_name: str, + consumer_id: Optional[str] = None, + is_backtest: bool = False, + min_idle_ms: int = 60000, + ) -> Optional[List[Tuple[str, Dict[str, Any]]]]: + """认领待处理消息(处理崩溃消费者的遗留消息) + + Args: + strategy_name: 策略名称 + consumer_id: 消费者ID + is_backtest: 是否为回测模式 + min_idle_ms: 最小空闲时间(毫秒),超过此时间的消息才会被认领 + + Returns: + 认领的消息列表,无消息或失败返回 None + """ + # 回测模式不需要认领 + if is_backtest: + return None + + stream_key = self._get_stream_key(strategy_name, is_backtest) + + if consumer_id is None: + consumer_id = self._generate_consumer_id() + + try: + # 获取待处理消息列表 + pending_info = self.r.xpending_range( + stream_key, self.CONSUMER_GROUP, min=min_idle_ms, max="+", count=10 + ) + + if not pending_info: + return None + + # 认领消息 + message_ids = [item["message_id"] for item in pending_info] + claimed = self.r.xclaim( + stream_key, + self.CONSUMER_GROUP, + consumer_id, + min_idle_time=min_idle_ms, + message_ids=message_ids, + ) + + if not claimed: + return None + + # 解析消息 + result = [] + for msg_id, msg_fields in claimed: + data = msg_fields.get("data", "{}") + try: + parsed_data = json.loads(data) + except json.JSONDecodeError: + parsed_data = {"raw_data": data} + + result.append((msg_id, parsed_data)) + + self.logger.info( + f"[消息认领] stream={stream_key}, id={msg_id}, " + f"consumer={consumer_id}, idle_ms>={min_idle_ms}" + ) + + return result if result else None + + except redis.RedisError as e: + self.logger.error(f"[消息认领失败] stream={stream_key}, error={str(e)}") + return None + except Exception as e: + self.logger.error( + f"[消息认领异常] stream={stream_key}, error={str(e)}", exc_info=True + ) + return None + + def _generate_consumer_id(self) -> str: + """生成消费者ID""" + hostname = socket.gethostname() + pid = os.getpid() + return f"{hostname}-{pid}" + + def get_stream_info( + self, strategy_name: str, is_backtest: bool = False + ) -> Dict[str, Any]: + """获取流信息 + + Args: + strategy_name: 策略名称 + is_backtest: 是否为回测模式 + + Returns: + 流信息字典 + """ + stream_key = self._get_stream_key(strategy_name, is_backtest) + + try: + length = self.r.xlen(stream_key) + info = {"length": length, "stream_key": stream_key} + + # 获取消费者组信息(仅实盘模式) + if not is_backtest: + try: + groups = self.r.xinfo_groups(stream_key) + info["groups"] = groups + except: + info["groups"] = [] + + return info + + except redis.RedisError as e: + self.logger.error(f"[获取流信息失败] stream={stream_key}, error={str(e)}") + return {"length": 0, "stream_key": stream_key, "error": str(e)} + except Exception as e: + self.logger.error( + f"[获取流信息异常] stream={stream_key}, error={str(e)}", exc_info=True + ) + return {"length": 0, "stream_key": stream_key, "error": str(e)} + + +# 便捷函数,用于快速发送消息 +def send_qmt_signal_to_stream( + strategy_name: str, + stock_code: str, + action: str, + price: float, + total_slots: int, + timestamp: str, + is_backtest: bool = False, + redis_config: Optional[Dict[str, Any]] = None, +) -> Optional[str]: + """发送 QMT 交易信号到 Redis Stream + + 这是一个便捷函数,用于快速发送标准格式的交易信号。 + + Args: + strategy_name: 策略名称 + stock_code: 股票代码 + action: 交易动作 (BUY/SELL) + price: 价格 + total_slots: 总槽位数 + timestamp: 时间戳 + is_backtest: 是否为回测 + redis_config: Redis 配置 + + Returns: + 消息ID,失败返回 None + """ + processor = StreamMessageProcessor(redis_config=redis_config) + + message = { + "strategy_name": strategy_name, + "stock_code": stock_code, + "action": action, + "price": price, + "total_slots": total_slots, + "timestamp": timestamp, + "is_backtest": is_backtest, + } + + return processor.send_message(strategy_name, message, is_backtest) diff --git a/qmt/qmt_engine.py b/qmt/qmt_engine.py index 02ee12c..235c9a3 100644 --- a/qmt/qmt_engine.py +++ b/qmt/qmt_engine.py @@ -17,6 +17,15 @@ from xtquant.xttrader import XtQuantTrader, XtQuantTraderCallback from xtquant.xttype import StockAccount from xtquant import xtconstant +# 导入 Redis Stream 消息处理器和日志模块 +try: + from .message_processor import StreamMessageProcessor + from .logger import QMTLogger +except ImportError: + # 当作为脚本直接运行时 + from message_processor import StreamMessageProcessor + from logger import QMTLogger + # ================= 0. Windows 补丁 ================= try: import ctypes @@ -473,19 +482,66 @@ class MultiEngineManager: self.start_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") self.is_scheduled_reconnecting = False # 定时重连调度器正在执行标志 self._initialized = True + # Stream 处理器和日志器将在 initialize 中创建 + self.stream_processor: Optional[StreamMessageProcessor] = None + self.qmt_logger: Optional[QMTLogger] = None def initialize(self, config_file="config.json"): - self._setup_logger() + self._setup_logger() # 先初始化 logger with open(config_file, "r", encoding="utf-8") as f: self.config = json.load(f) - self.r = redis.Redis(**self.config["redis"], decode_responses=True) + # 从 .env.local 加载 Redis 配置 + redis_config = self._load_redis_config() + self.r = redis.Redis(**redis_config, decode_responses=True) self.pos_manager = PositionManager(self.r) + # 初始化 Redis Stream 处理器 + self.stream_processor = StreamMessageProcessor(redis_client=self.r) + self.qmt_logger = QMTLogger(name="QMT_Engine_Stream") + self.logger.info("Redis Stream 处理器初始化完成") + for t_cfg in self.config.get("qmt_terminals", []): unit = TradingUnit(t_cfg) unit.connect() self.units[unit.qmt_id] = unit + def _load_redis_config(self) -> Dict[str, Any]: + """从 .env.local 加载 Redis 配置""" + # 尝试加载 python-dotenv + try: + from dotenv import load_dotenv + + # 尝试多个路径 + env_paths = [ + os.path.join(os.path.dirname(os.path.abspath(__file__)), "config", ".env.local"), + os.path.join(os.path.dirname(__file__), "config", ".env.local"), + os.path.join(os.path.dirname(__file__), "..", "config", ".env.local"), + "/qmt/config/.env.local", + "config/.env.local", + ] + + loaded = False + for env_path in env_paths: + if os.path.exists(env_path): + load_dotenv(env_path) + self.logger.info(f"[Config] 加载 Redis 配置: {env_path}") + loaded = True + break + + if not loaded: + self.logger.warning("[Config] 警告: 未找到 .env.local 文件,使用默认配置") + except ImportError: + self.logger.warning("[Config] 警告: 未安装 python-dotenv,使用默认配置") + + # 从环境变量读取 Redis 配置 + redis_config = { + "host": os.getenv("REDIS_HOST", "localhost"), + "port": int(os.getenv("REDIS_PORT", "6379")), + "password": os.getenv("REDIS_PASSWORD") or None, + "db": int(os.getenv("REDIS_DB", "0")), + } + + return redis_config def _setup_logger(self): log_dir = "logs" @@ -494,8 +550,8 @@ class MultiEngineManager: log_file = os.path.join( log_dir, f"{datetime.date.today().strftime('%Y-%m-%d')}.log" ) - logger = logging.getLogger("QMT_Engine") - logger.setLevel(logging.INFO) + self.logger = logging.getLogger("QMT_Engine") + self.logger.setLevel(logging.INFO) # 确保日志流为 UTF-8 fmt = logging.Formatter( "[%(asctime)s] [%(threadName)s] %(message)s", "%H:%M:%S" @@ -504,9 +560,8 @@ class MultiEngineManager: fh.setFormatter(fmt) sh = logging.StreamHandler(sys.stdout) sh.setFormatter(fmt) - logger.addHandler(fh) - logger.addHandler(sh) - + self.logger.addHandler(fh) + self.logger.addHandler(sh) def get_strategies_by_terminal(self, qmt_id): return [ s @@ -632,37 +687,147 @@ class MultiEngineManager: time.sleep(10) def process_route(self, strategy_name): + """处理策略消息路由 - 使用 Redis Stream + + 从 Redis Stream 消费消息,处理成功后 ACK,失败则进入失败队列。 + """ strat_cfg = self.config["strategies"].get(strategy_name) unit = self.units.get(strat_cfg.get("qmt_id")) if not unit or not unit.callback or not unit.callback.is_connected: return - msg_json = self.r.lpop(f"{strategy_name}_real") - if not msg_json: + # 使用 StreamMessageProcessor 消费消息 + if not self.stream_processor: + self.logger.error("[process_route] Stream处理器未初始化") return try: - data = json.loads(msg_json) - # 严格校验消息日期 - if data.get("timestamp", "").split(" ")[ - 0 - ] != datetime.date.today().strftime("%Y-%m-%d"): + # 消费消息 (非阻塞,立即返回) + messages = self.stream_processor.consume_message( + strategy_name=strategy_name, + consumer_id=None, # 自动生成 + is_backtest=False, + block_ms=100, # 短阻塞,快速返回 + ) + + if not messages: return - if data["action"] == "BUY": - self._execute_buy(unit, strategy_name, data) - elif data["action"] == "SELL": - self._execute_sell(unit, strategy_name, data) - except json.JSONDecodeError as e: - self.logger.error( - f"[{strategy_name}] JSON解析失败: {e}, 消息: {msg_json[:200]}" - ) - except KeyError as e: - self.logger.error(f"[{strategy_name}] 消息缺少必要字段: {e}") + # 处理每条消息 + for msg_id, data in messages: + try: + # 1. 记录消息接收日志 + stream_key = f"qmt:{strategy_name}:real" + self.qmt_logger.log_message_receive(stream_key, msg_id, data) + + # 2. 严格校验消息日期 + msg_date = data.get("timestamp", "").split(" ")[0] + today_str = datetime.date.today().strftime("%Y-%m-%d") + + if msg_date != today_str: + self.qmt_logger.log_validation( + validation_type="date_check", + strategy_name=strategy_name, + details={"msg_date": msg_date, "today": today_str}, + result=False, + ) + # 日期不符的消息也 ACK,避免重复处理 + self.stream_processor.ack_message( + strategy_name, msg_id, is_backtest=False + ) + continue + + self.qmt_logger.log_validation( + validation_type="date_check", + strategy_name=strategy_name, + details={"msg_date": msg_date}, + result=True, + ) + + # 3. 执行交易动作 + action = data.get("action") + + # 获取策略配置,确定下单模式 + strat_cfg = self.config["strategies"].get(strategy_name, {}) + order_mode = strat_cfg.get("order_mode", "slots") + + if action == "BUY": + self.qmt_logger.log_validation( + validation_type="action_check", + strategy_name=strategy_name, + details={"action": "BUY", "code": data.get("stock_code"), "order_mode": order_mode}, + result=True, + ) + # 根据下单模式执行相应逻辑 + if order_mode == "percentage": + self._execute_percentage_buy(unit, strategy_name, data) + else: + self._execute_buy(unit, strategy_name, data) + elif action == "SELL": + self.qmt_logger.log_validation( + validation_type="action_check", + strategy_name=strategy_name, + details={"action": "SELL", "code": data.get("stock_code"), "order_mode": order_mode}, + result=True, + ) + # 根据下单模式执行相应逻辑 + if order_mode == "percentage": + self._execute_percentage_sell(unit, strategy_name, data) + else: + self._execute_sell(unit, strategy_name, data) + else: + self.qmt_logger.log_validation( + validation_type="action_check", + strategy_name=strategy_name, + details={"action": action}, + result=False, + ) + self.logger.warning(f"[{strategy_name}] 未知动作: {action}") + + # 4. 确认消息已处理 + ack_success = self.stream_processor.ack_message( + strategy_name, msg_id, is_backtest=False + ) + self.qmt_logger.log_ack(stream_key, msg_id, ack_success) + + except json.JSONDecodeError as e: + error_msg = f"JSON解析失败: {e}" + self.logger.error( + f"[{strategy_name}] {error_msg}, 消息ID: {msg_id}" + ) + self.qmt_logger.log_failure(stream_key, msg_id, error_msg) + # 解析失败的消息也发送 ACK,避免死循环 + self.stream_processor.ack_message( + strategy_name, msg_id, is_backtest=False + ) + + except KeyError as e: + error_msg = f"消息缺少必要字段: {e}" + self.logger.error(f"[{strategy_name}] {error_msg}") + self.qmt_logger.log_failure(stream_key, msg_id, error_msg) + self.stream_processor.send_to_failure_queue( + strategy_name, data, error_msg + ) + # 发送失败队列后 ACK + self.stream_processor.ack_message( + strategy_name, msg_id, is_backtest=False + ) + + except Exception as e: + error_msg = f"消息处理异常: {str(e)}" + self.logger.error(f"[{strategy_name}] {error_msg}", exc_info=True) + self.qmt_logger.log_failure(stream_key, msg_id, error_msg) + # 异常消息进入失败队列 + self.stream_processor.send_to_failure_queue( + strategy_name, data, error_msg + ) + # 发送失败队列后 ACK + self.stream_processor.ack_message( + strategy_name, msg_id, is_backtest=False + ) + except Exception as e: - self.logger.error( - f"[{strategy_name}] 消息处理异常: {str(e)}", exc_info=True - ) + self.logger.error(f"[process_route] 消费消息异常: {str(e)}", exc_info=True) def _execute_buy(self, unit, strategy_name, data): strat_cfg = self.config["strategies"][strategy_name] @@ -719,6 +884,15 @@ class MultiEngineManager: if vol < 100: return + # 记录订单执行请求 + self.qmt_logger.log_order_execution( + strategy_name=strategy_name, + stock_code=data["stock_code"], + action="BUY", + volume=vol, + price=price, + ) + oid = unit.xt_trader.order_stock( unit.acc_obj, data["stock_code"], @@ -735,6 +909,26 @@ class MultiEngineManager: self.logger.info( f"√√√ [{unit.alias}] {strategy_name} 下单买入: {data['stock_code']} {vol}股 @ {price}" ) + # 记录订单执行成功 + self.qmt_logger.log_order_execution( + strategy_name=strategy_name, + stock_code=data["stock_code"], + action="BUY", + volume=vol, + price=price, + order_id=oid, + ) + else: + error_msg = "下单请求被拒绝 (Result=-1)" + self.logger.error(f"[{strategy_name}] {error_msg}") + self.qmt_logger.log_order_execution( + strategy_name=strategy_name, + stock_code=data["stock_code"], + action="BUY", + volume=vol, + price=price, + error=error_msg, + ) except: self.logger.error(traceback.format_exc()) @@ -785,6 +979,15 @@ class MultiEngineManager: ) price = round(float(data["price"]) + offset, 3) + # 记录订单执行请求 + self.qmt_logger.log_order_execution( + strategy_name=strategy_name, + stock_code=data["stock_code"], + action="SELL", + volume=final_vol, + price=price, + ) + oid = unit.xt_trader.order_stock( unit.acc_obj, data["stock_code"], @@ -800,9 +1003,198 @@ class MultiEngineManager: self.logger.info( f"√√√ [{unit.alias}] {strategy_name} 下单卖出: {data['stock_code']} {final_vol}股 @ {price}" ) + # 记录订单执行成功 + self.qmt_logger.log_order_execution( + strategy_name=strategy_name, + stock_code=data["stock_code"], + action="SELL", + volume=final_vol, + price=price, + order_id=oid, + ) + else: + error_msg = "下单请求被拒绝 (Result=-1)" + self.logger.error(f"[{strategy_name}] {error_msg}") + self.qmt_logger.log_order_execution( + strategy_name=strategy_name, + stock_code=data["stock_code"], + action="SELL", + volume=final_vol, + price=price, + error=error_msg, + ) except: self.logger.error(traceback.format_exc()) + def _execute_percentage_buy(self, unit, strategy_name, data): + """处理百分比模式的买入逻辑""" + strat_cfg = self.config["strategies"][strategy_name] + + # 获取目标持仓百分比 + position_pct = float(data.get("position_pct", 0)) + if position_pct <= 0: + self.logger.warning(f"[{strategy_name}] 百分比模式买入: position_pct 无效 ({position_pct})") + return + + self.logger.info(f"[{strategy_name}] [百分比模式] 处理买入: {data['stock_code']}, 目标占比: {position_pct}") + + try: + asset = unit.xt_trader.query_stock_asset(unit.acc_obj) + if not asset: + self.logger.error(f"[{strategy_name}] API 错误: query_stock_asset 返回 None") + return + + total_asset = asset.total_asset + available_cash = asset.cash + + self.logger.info(f"[{strategy_name}] [百分比模式] 账户总资产: {total_asset:.2f}, 可用资金: {available_cash:.2f}") + + # 计算目标金额 + target_amount = total_asset * position_pct + actual_amount = min(target_amount, available_cash * 0.98) # 预留手续费滑点 + + self.logger.info(f"[{strategy_name}] [百分比模式] 目标金额: {target_amount:.2f}, 实际可用: {actual_amount:.2f}") + + # 检查最小金额限制 + if actual_amount < 2000: + self.logger.warning(f"[{strategy_name}] [百分比模式] 拦截买入: 金额过小 ({actual_amount:.2f} < 2000)") + return + + # 价格校验 + price = float(data.get("price", 0)) + offset = strat_cfg.get("execution", {}).get("buy_price_offset", 0.0) + price = round(price + offset, 3) + + if price <= 0: + self.logger.warning(f"[{strategy_name}] [百分比模式] 价格异常: {price},强制设为1.0") + price = 1.0 + + # 计算股数 + vol = int(actual_amount / price / 100) * 100 + self.logger.info(f"[{strategy_name}] [百分比模式] 计算股数: 资金{actual_amount:.2f} / 价格{price} -> {vol}股") + + if vol < 100: + self.logger.warning(f"[{strategy_name}] [百分比模式] 拦截买入: 股数不足 100 ({vol})") + return + + # 记录订单执行请求 + self.qmt_logger.log_order_execution( + strategy_name=strategy_name, + stock_code=data["stock_code"], + action="BUY", + volume=vol, + price=price, + ) + + oid = unit.xt_trader.order_stock( + unit.acc_obj, + data["stock_code"], + xtconstant.STOCK_BUY, + vol, + xtconstant.FIX_PRICE, + price, + strategy_name, + "PyBuyPct", + ) + + if oid != -1: + unit.order_cache[oid] = (strategy_name, data["stock_code"], "BUY") + self.logger.info(f"√√√ [{unit.alias}] [{strategy_name}] [百分比模式] 下单买入: {data['stock_code']} {vol}股 @ {price}") + # 记录订单执行成功 + self.qmt_logger.log_order_execution( + strategy_name=strategy_name, + stock_code=data["stock_code"], + action="BUY", + volume=vol, + price=price, + order_id=oid, + ) + else: + error_msg = "下单请求被拒绝 (Result=-1)" + self.logger.error(f"[{strategy_name}] [百分比模式] {error_msg}") + self.qmt_logger.log_order_execution( + strategy_name=strategy_name, + stock_code=data["stock_code"], + action="BUY", + volume=vol, + price=price, + error=error_msg, + ) + except: + self.logger.error(traceback.format_exc()) + + def _execute_percentage_sell(self, unit, strategy_name, data): + """处理百分比模式的卖出逻辑(清仓)""" + self.logger.info(f"[{strategy_name}] [百分比模式] 处理卖出: {data['stock_code']} (清仓)") + + try: + # 查询实盘持仓 + real_pos = unit.xt_trader.query_stock_positions(unit.acc_obj) + if real_pos is None: + self.logger.error(f"[{strategy_name}] [百分比模式] API 错误: query_stock_positions 返回 None") + return + + rp = next((p for p in real_pos if p.stock_code == data["stock_code"]), None) + can_use = rp.can_use_volume if rp else 0 + + self.logger.info(f"[{strategy_name}] [百分比模式] 股票 {data['stock_code']} 实盘可用持仓: {can_use}") + + if can_use <= 0: + self.logger.warning(f"[{strategy_name}] [百分比模式] 拦截卖出: 无可用持仓") + return + + # 执行清仓 + price = float(data.get("price", 0)) + offset = self.config["strategies"][strategy_name].get("execution", {}).get("sell_price_offset", 0.0) + price = round(price + offset, 3) + + self.logger.info(f"[{strategy_name}] [百分比模式] 执行清仓: {data['stock_code']} @ {price}, 数量: {can_use}") + + # 记录订单执行请求 + self.qmt_logger.log_order_execution( + strategy_name=strategy_name, + stock_code=data["stock_code"], + action="SELL", + volume=can_use, + price=price, + ) + + oid = unit.xt_trader.order_stock( + unit.acc_obj, + data["stock_code"], + xtconstant.STOCK_SELL, + can_use, + xtconstant.FIX_PRICE, + price, + strategy_name, + "PySellPct", + ) + + if oid != -1: + unit.order_cache[oid] = (strategy_name, data["stock_code"], "SELL") + self.logger.info(f"√√√ [{unit.alias}] [{strategy_name}] [百分比模式] 下单卖出: {data['stock_code']} {can_use}股 @ {price}") + # 记录订单执行成功 + self.qmt_logger.log_order_execution( + strategy_name=strategy_name, + stock_code=data["stock_code"], + action="SELL", + volume=can_use, + price=price, + order_id=oid, + ) + else: + error_msg = "下单请求被拒绝 (Result=-1)" + self.logger.error(f"[{strategy_name}] [百分比模式] {error_msg}") + self.qmt_logger.log_order_execution( + strategy_name=strategy_name, + stock_code=data["stock_code"], + action="SELL", + volume=can_use, + price=price, + error=error_msg, + ) + except: + self.logger.error(traceback.format_exc()) def verify_connection(self, timeout=5): """验证物理连接是否有效""" try: diff --git a/qmt/qmt_functionality.md b/qmt/qmt_functionality.md index cdf8741..820c71a 100644 --- a/qmt/qmt_functionality.md +++ b/qmt/qmt_functionality.md @@ -4,9 +4,9 @@ QMT 模块是 NewStock 量化交易系统的实盘交易执行模块,通过 `xtquant` 库连接 QMT 交易终端,实现自动化交易功能。该模块采用多终端架构设计,支持同时管理多个 QMT 终端实例,并提供 Web 仪表盘和 RESTful API 接口进行监控和操作。 -系统核心特性包括:多终端并行管理、异步订单处理、断线自动重连、收盘自动清算、实时心跳检测等。所有交易信号通过 Redis 消息队列接收,确保交易指令的可靠传递和执行。 +系统核心特性包括:多终端并行管理、异步订单处理、断线自动重连、收盘自动清算、实时心跳检测等。所有交易信号通过 Redis Stream 消息队列接收,确保交易指令的可靠传递和执行。 -系统分为**信号发送端**和**交易执行端**两部分。信号发送端(`qmt_signal_sender.py`)运行在聚宽策略环境中,将策略产生的买卖信号推送至 Redis 队列;交易执行端(`qmt_engine.py` + `run.py`)运行在本地,从 Redis 消费信号并通过 QMT 终端执行实盘交易。 +系统分为**信号发送端**和**交易执行端**两部分。信号发送端(`qmt_sender.py`)运行在聚宽策略环境中,将策略产生的买卖信号推送至 Redis Stream;交易执行端(`qmt_engine.py` + `run.py`)运行在本地,从 Redis Stream 消费信号并通过 QMT 终端执行实盘交易。 ## 2. 核心组件 @@ -16,8 +16,10 @@ QMT 模块是 NewStock 量化交易系统的实盘交易执行模块,通过 `x |------|------| | [`run.py`](run.py) | 系统启动入口,负责初始化多终端管理器并启动 API 服务 | | [`qmt_engine.py`](qmt_engine.py) | 核心引擎模块,包含多终端管理器和交易执行单元 | -| [`qmt_trader.py`](qmt_trader.py) | 旧版单终端交易引擎(保留兼容) | -| [`qmt_signal_sender.py`](qmt_signal_sender.py) | 信号发送端,运行于聚宽策略侧,将交易信号推送至 Redis 队列 | +| [`qmt_sender.py`](qmt_sender.py) | 统一信号发送端,支持槽位模式和百分比模式,运行于聚宽策略侧 | +| [`backtest_consumer.py`](backtest_consumer.py) | 回测消息消费者,模拟交易执行并记录完整日志 | +| [`message_processor.py`](message_processor.py) | Redis Stream 消息处理器,封装消息发送、消费、确认等功能 | +| [`logger.py`](logger.py) | 细粒度日志模块,追踪消息处理全流程 | | [`api_server.py`](api_server.py) | FastAPI Web 服务,提供 RESTful API 接口 | | [`dashboard.html`](dashboard.html) | Web 仪表盘前端页面 | | [`start.bat`](start.bat) | Windows 启动脚本 | @@ -37,14 +39,30 @@ QMT 模块是 NewStock 量化交易系统的实盘交易执行模块,通过 `x | `UnitCallback` | 终端回调处理器,处理成交回报和错误通知 | | `TerminalStatus` | 终端状态数据类,封装终端连接状态信息 | -#### qmt_trader.py +#### qmt_sender.py + +| 函数 | 功能说明 | +|------|----------| +| `send_qmt_signal()` | 发送槽位模式信号(基于 total_slots) | +| `send_qmt_percentage_signal()` | 发送百分比模式信号(基于 position_pct) | + +#### backtest_consumer.py | 类名 | 功能说明 | |------|----------| -| `SystemState` | 全局状态管理器,维护交易系统运行状态 | -| `PositionManager` | 虚拟持仓管理器,管理策略与股票的持仓映射 | -| `DailySettlement` | 日终清算处理器,处理收盘后的撤单和持仓修正 | -| `MyXtQuantTraderCallback` | QMT 交易回调,处理成交和错误事件 | +| `BacktestConsumer` | 回测消息消费者,支持守护模式和单次运行模式 | + +#### message_processor.py + +| 类名 | 功能说明 | +|------|----------| +| `StreamMessageProcessor` | Redis Stream 消息处理器,支持消息发送、消费、确认、失败处理 | + +#### logger.py + +| 类名 | 功能说明 | +|------|----------| +| `QMTLogger` | 细粒度日志记录器,追踪消息接收、解析、校验、执行、确认全流程 | ## 3. 功能详细说明 @@ -56,7 +74,7 @@ QMT 模块是 NewStock 量化交易系统的实盘交易执行模块,通过 `x ### 3.2 交易消息处理 -交易信号通过 Redis 消息队列传递,每个策略对应一个独立的队列。消息格式为 JSON 对象,包含股票代码、操作类型、价格、时间戳等字段。系统对每条消息进行严格校验,包括日期校验、时间戳校验、必填字段校验等,确保只有当天的有效指令才会被执行。 +交易信号通过 Redis Stream 消息队列传递,每个策略对应一个独立的 Stream。消息格式为 JSON 对象,包含股票代码、操作类型、价格、时间戳等字段。系统对每条消息进行严格校验,包括日期校验、时间戳校验、必填字段校验等,确保只有当天的有效指令才会被执行。 买入逻辑支持两种模式: @@ -88,7 +106,13 @@ QMT 模块是 NewStock 量化交易系统的实盘交易执行模块,通过 `x 系统采用增强型日志系统,支持文件和控制台双路输出。日志格式包含时间戳、线程名、级别和消息内容,便于追踪问题。文件日志按日期命名,自动存放在 `logs/` 目录下。控制台输出强制刷新流,确保在 Windows 环境下日志实时显示。 -日志级别分为 INFO、WARNING、ERROR 三级,重要操作和状态变化都会记录。交易相关日志特别标注策略名称和股票代码,方便后续分析和审计。 +新增 `logger.py` 模块提供细粒度日志记录,追踪消息处理全流程: +- 消息接收(`log_message_receive`) +- 消息解析(`log_message_parse`) +- 业务校验(`log_validation`) +- 订单执行(`log_order_execution`) +- 消息确认(`log_message_ack`) +- 失败处理(`log_failure`) ## 4. API 接口列表 @@ -234,6 +258,21 @@ QMT 模块是 NewStock 量化交易系统的实盘交易执行模块,通过 `x } ``` +### 5.3 环境变量配置 + +系统支持通过 `.env.local` 文件或环境变量配置以下参数: + +| 变量名 | 默认值 | 说明 | +|--------|--------|------| +| `REDIS_HOST` | localhost | Redis 主机地址 | +| `REDIS_PORT` | 6379 | Redis 端口 | +| `REDIS_PASSWORD` | None | Redis 密码 | +| `REDIS_DB` | 0 | Redis 数据库 | +| `BACKTEST_CONSUMER_ID` | backtest-consumer-1 | 回测消费者 ID | +| `BACKTEST_STRATEGIES` | "" | 默认策略列表,逗号分隔 | +| `LOG_LEVEL` | DEBUG | 日志级别 | +| `LOG_FILE` | logs/backtest_consumer.log | 日志文件路径 | + ## 6. Web 仪表盘功能 ### 6.1 功能概览 @@ -256,16 +295,20 @@ Web 仪表盘基于 Vue 3 和 Naive UI 组件库开发,提供可视化的系 仪表盘默认访问地址为 `http://localhost:8001`,该地址在系统启动时打印在控制台。首次访问时会自动加载所有终端状态、持仓信息和系统日志。 -## 7. 信号发送端(qmt_signal_sender.py) +## 7. 信号发送端(qmt_sender.py) ### 7.1 模块定位 -`qmt_signal_sender.py` 是 QMT 交易系统的**信号生产端**,部署在聚宽(JoinQuant)策略运行环境中。它负责将策略产生的买卖信号序列化后推送到 Redis 队列,由本地 QMT 交易引擎消费并执行。该模块是连接"策略研究/回测平台"与"实盘交易执行"的桥梁。 +`qmt_sender.py` 是 QMT 交易系统的**信号生产端**,部署在聚宽(JoinQuant)策略运行环境中。它负责将策略产生的买卖信号序列化后推送到 Redis Stream,由本地 QMT 交易引擎消费并执行。该模块是连接"策略研究/回测平台"与"实盘交易执行"的桥梁。 + +该模块统一了槽位模式和百分比模式,通过不同函数发送不同类型的信号。 ### 7.2 核心函数 #### `send_qmt_signal(code, target_total_slots, price, context, redis_config)` +发送槽位模式信号。 + | 参数 | 类型 | 说明 | |------|------|------| | `code` | str | 股票代码,聚宽格式(如 `000001.XSHE`、`600519.XSHG`) | @@ -274,6 +317,20 @@ Web 仪表盘基于 Vue 3 和 Naive UI 组件库开发,提供可视化的系 | `context` | object | 聚宽上下文对象,提供 `run_params.type`(运行类型)和 `current_dt`(当前时间) | | `redis_config` | dict | Redis 连接配置,包含 `host`、`port`、`password`、`db`、`strategy_name` 等字段 | +#### `send_qmt_percentage_signal(code, position_pct, action, price, is_backtest, timestamp, redis_config)` + +发送百分比模式信号。 + +| 参数 | 类型 | 说明 | +|------|------|------| +| `code` | str | 股票代码,聚宽格式(如 `000001.XSHE`、`600519.XSHG`) | +| `position_pct` | float | 目标持仓占总资产的比例,范围 0.0 ~ 1.0(如 0.2 表示 20%) | +| `action` | str | 交易动作,固定为 `"BUY"` 或 `"SELL"` | +| `price` | float | 当前最新价格,用于实盘限价单参考 | +| `is_backtest` | bool | 是否为回测模式(True/False) | +| `timestamp` | str | 时间戳字符串,格式 `"YYYY-MM-DD HH:MM:SS"` | +| `redis_config` | dict | Redis 连接配置,包含 `host`、`port`、`password`、`db`、`strategy_name` 等字段 | + ### 7.3 处理流程 ``` @@ -285,20 +342,20 @@ Web 仪表盘基于 Vue 3 和 Naive UI 组件库开发,提供可视化的系 └─ 回测模式 → 限制最多发送 10 条(防止回测刷爆队列) │ ▼ -2. 建立 Redis 连接(socket_timeout=1s) +2. 建立 Redis Stream 连接 │ ▼ 3. 数据转换与规范化 ├─ 股票代码格式转换:.XSHE → .SZ,.XSHG → .SH - └─ 动作判定:target_total_slots > 0 → BUY,= 0 → SELL + └─ 动作判定(槽位模式):target_total_slots > 0 → BUY,= 0 → SELL │ ▼ 4. 构建 JSON 消息体 │ ▼ -5. 队列路由 - ├─ 回测 → {strategy_name}_backtest(TTL: 1 小时) - └─ 实盘 → {strategy_name}_real(TTL: 7 天) +5. Stream 路由 + ├─ 回测 → qmt:{strategy_name}:backtest + └─ 实盘 → qmt:{strategy_name}:real │ ▼ 6. 控制台日志输出 @@ -306,8 +363,9 @@ Web 仪表盘基于 Vue 3 和 Naive UI 组件库开发,提供可视化的系 ### 7.4 消息格式 -发送到 Redis 队列的 JSON 消息结构: +发送到 Redis Stream 的 JSON 消息结构: +**槽位模式:** ```json { "strategy_name": "my_strategy", @@ -320,94 +378,7 @@ Web 仪表盘基于 Vue 3 和 Naive UI 组件库开发,提供可视化的系 } ``` -| 字段 | 类型 | 说明 | -|------|------|------| -| `strategy_name` | str | 策略名称,来自 `redis_config['strategy_name']`,用于队列路由和持仓管理 | -| `stock_code` | str | QMT 格式的股票代码(`.SZ` / `.SH`) | -| `action` | str | 交易动作,`BUY` 或 `SELL` | -| `price` | float | 信号触发时的最新价格 | -| `total_slots` | int | 策略的总槽位数(BUY 时为策略设定值,SELL 时为 0) | -| `timestamp` | str | 信号生成时间,格式 `YYYY-MM-DD HH:MM:SS` | -| `is_backtest` | bool | 是否为回测环境发出的信号 | - -### 7.5 买卖意图判定逻辑 - -信号发送端不直接区分"买入函数"和"卖出函数",而是通过 `target_total_slots` 参数的值进行语义推断: - -- **`target_total_slots > 0`**(BUY):策略意向持有该股票,`total_slots` 传递策略的总持仓上限,供交易引擎计算单只股票的资金分配。 -- **`target_total_slots = 0`**(SELL):策略意向清仓该股票,释放所占槽位。 - -### 7.6 回测流量控制 - -模块级全局变量 `_BACKTEST_SEND_COUNT` 用于限制回测模式下的信号发送数量,上限为 10 条。这一机制防止长周期回测期间大量无效信号涌入 Redis 队列,回测队列的 TTL 也相应缩短为 1 小时(实盘为 7 天)。 - -### 7.7 队列命名规则 - -| 运行模式 | 队列名格式 | TTL | -|----------|-----------|-----| -| 实盘 | `{strategy_name}_real` | 604800 秒(7 天) | -| 回测 | `{strategy_name}_backtest` | 3600 秒(1 小时) | - -### 7.8 股票代码格式转换 - -| 来源平台 | 格式 | 示例 | -|----------|------|------| -| 聚宽 | `.XSHE` / `.XSHG` | `000001.XSHE`、`600519.XSHG` | -| QMT | `.SZ` / `.SH` | `000001.SZ`、`600519.SH` | - -## 8. 百分比下单信号发送端(qmt_percentage_sender.py) - -### 8.1 模块定位 - -`qmt_percentage_sender.py` 是基于**仓位百分比**的 QMT 信号发送端,与槽位模式的 `qmt_signal_sender.py` 并行存在。该模块用于配置为 `order_mode: "percentage"` 的策略,通过指定目标持仓占账户总资产的比例来触发交易。 - -### 8.2 核心函数 - -#### `send_qmt_percentage_signal(code, position_pct, action, price, is_backtest, timestamp, redis_config)` - -| 参数 | 类型 | 说明 | -|------|------|------| -| `code` | str | 股票代码,聚宽格式(如 `000001.XSHE`、`600519.XSHG`) | -| `position_pct` | float | 目标持仓占总资产的比例,范围 0.0 ~ 1.0(如 0.2 表示 20%) | -| `action` | str | 交易动作,固定为 `"BUY"` 或 `"SELL"` | -| `price` | float | 当前最新价格,用于实盘限价单参考 | -| `is_backtest` | bool | 是否为回测模式(True/False) | -| `timestamp` | str | 时间戳字符串,格式 `"YYYY-MM-DD HH:MM:SS"` | -| `redis_config` | dict | Redis 连接配置,包含 `host`、`port`、`password`、`db`、`strategy_name` 等字段 | - -### 8.3 处理流程 - -``` -策略触发信号 - │ - ▼ -1. 环境判断与流量控制 - ├─ 实盘模式 → 直接通过 - └─ 回测模式 → 限制最多发送 10 条(防止回测刷爆队列) - │ - ▼ -2. 建立 Redis 连接(socket_timeout=1s) - │ - ▼ -3. 数据转换与规范化 - └─ 股票代码格式转换:.XSHE → .SZ,.XSHG → .SH - │ - ▼ -4. 构建 JSON 消息体(包含 position_pct 字段) - │ - ▼ -5. 队列路由 - ├─ 回测 → {strategy_name}_backtest(TTL: 1 小时) - └─ 实盘 → {strategy_name}_real(TTL: 7 天) - │ - ▼ -6. 控制台日志输出 -``` - -### 8.4 消息格式 - -发送到 Redis 队列的 JSON 消息结构: - +**百分比模式:** ```json { "strategy_name": "my_strategy", @@ -426,47 +397,43 @@ Web 仪表盘基于 Vue 3 和 Naive UI 组件库开发,提供可视化的系 | `stock_code` | str | QMT 格式的股票代码(`.SZ` / `.SH`) | | `action` | str | 交易动作,`BUY` 或 `SELL` | | `price` | float | 信号触发时的最新价格 | -| `position_pct` | float | 目标持仓占账户总资产的比例,范围 0.0 ~ 1.0 | +| `total_slots` | int | 策略的总槽位数(槽位模式) | +| `position_pct` | float | 目标持仓占账户总资产的比例(百分比模式) | | `timestamp` | str | 信号生成时间,格式 `YYYY-MM-DD HH:MM:SS` | | `is_backtest` | bool | 是否为回测环境发出的信号 | -### 8.5 买卖意图判定逻辑 +### 7.5 买卖意图判定逻辑 -与槽位模式不同,百分比模式需要**显式指定**交易动作: +**槽位模式**:通过 `target_total_slots` 参数的值进行语义推断: +- **`target_total_slots > 0`**(BUY):策略意向持有该股票,`total_slots` 传递策略的总持仓上限,供交易引擎计算单只股票的资金分配。 +- **`target_total_slots = 0`**(SELL):策略意向清仓该股票,释放所占槽位。 +**百分比模式**:需要**显式指定**交易动作: - **`action = "BUY"`**:策略意向买入该股票,目标持仓占比为 `position_pct`。交易引擎根据账户总资产计算目标金额,然后转换为具体股数下单。 - **`action = "SELL"`**:策略意向清仓该股票。百分比模式下卖出采用简化逻辑,直接执行清仓操作。 -### 8.6 买入计算公式 +### 7.6 回测流量控制 -当 QMT 端接收到百分比模式的买入信号时,按以下公式计算买入股数: +模块级全局变量 `_BACKTEST_SEND_COUNT` 用于限制回测模式下的信号发送数量,上限为 10 条。这一机制防止长周期回测期间大量无效信号涌入 Redis 队列。 -``` -目标金额 = 账户总资产 × position_pct -可用金额 = min(目标金额, 可用资金) -买入股数 = int(可用金额 / 价格 / 100) × 100 -``` +### 7.7 Stream 命名规则 -**边界处理:** -- 单笔金额 < 2000 元 → 拦截不下单 -- 计算股数 < 100 股 → 拦截不下单 -- 价格 ≤ 0 → 强制设为 1.0(仅测试用) +| 运行模式 | Stream 键名格式 | +|----------|----------------| +| 实盘 | `qmt:{strategy_name}:real` | +| 回测 | `qmt:{strategy_name}:backtest` | -### 8.7 与槽位模式的对比 +### 7.8 股票代码格式转换 -| 特性 | 槽位模式 (slots) | 百分比模式 (percentage) | -|------|------------------|------------------------| -| 核心参数 | `total_slots` | `position_pct` | -| 持仓限制 | 有(同时持仓数量限制) | 无 | -| 资金分配 | 按剩余槽位均分资金 | 按总资产比例计算 | -| 卖出逻辑 | 按持仓数量计算 | 清仓 | -| 配置方式 | 配置文件设置 `order_mode: "slots"` | 配置文件设置 `order_mode: "percentage"` | -| 信号发送 | `send_qmt_signal()` | `send_qmt_percentage_signal()` | +| 来源平台 | 格式 | 示例 | +|----------|------|------| +| 聚宽 | `.XSHE` / `.XSHG` | `000001.XSHE`、`600519.XSHG` | +| QMT | `.SZ` / `.SH` | `000001.SZ`、`600519.SH` | -### 8.8 使用示例 +### 7.9 使用示例 ```python -from qmt_percentage_sender import send_qmt_percentage_signal +from qmt_sender import send_qmt_signal, send_qmt_percentage_signal # Redis 配置 redis_config = { @@ -474,10 +441,19 @@ redis_config = { "port": 6379, "password": None, "db": 0, - "strategy_name": "MyPercentageStrategy" + "strategy_name": "MyStrategy" } -# 买入信号:目标持仓占账户总资产的 20% +# 槽位模式买入信号 +send_qmt_signal( + code="000001.XSHE", + target_total_slots=5, + price=15.5, + context=context, # 聚宽上下文 + redis_config=redis_config +) + +# 百分比模式买入信号(目标持仓 20%) send_qmt_percentage_signal( code="000001.XSHE", position_pct=0.2, @@ -487,22 +463,43 @@ send_qmt_percentage_signal( timestamp="2026-02-17 14:30:00", redis_config=redis_config ) - -# 卖出信号:清仓 -send_qmt_percentage_signal( - code="000001.XSHE", - position_pct=0, - action="SELL", - price=15.8, - is_backtest=False, - timestamp="2026-02-17 14:35:00", - redis_config=redis_config -) ``` +## 8. 回测消息消费者(backtest_consumer.py) + +### 8.1 模块定位 + +`backtest_consumer.py` 是独立的回测消息消费脚本,用于消费回测消息流、记录完整的处理流程日志、模拟订单执行(不执行真实交易),并支持 ACK 确认消息。 + +### 8.2 使用方式 + +```bash +# 守护模式(持续运行,处理所有配置的策略) +python backtest_consumer.py + +# 单次运行模式(处理一次后退出) +python backtest_consumer.py --once + +# 指定策略运行 +python backtest_consumer.py --strategy StrategyA +python backtest_consumer.py --once --strategy StrategyA,StrategyB +``` + +### 8.3 配置说明 + +可通过环境变量或 `.env.local` 文件配置: +- `REDIS_HOST`: Redis 主机地址(默认: localhost) +- `REDIS_PORT`: Redis 端口(默认: 6379) +- `REDIS_PASSWORD`: Redis 密码(默认: None) +- `REDIS_DB`: Redis 数据库(默认: 0) +- `BACKTEST_CONSUMER_ID`: 消费者ID(默认: backtest-consumer-1) +- `BACKTEST_STRATEGIES`: 默认策略列表,逗号分隔 +- `LOG_LEVEL`: 日志级别(默认: DEBUG) +- `LOG_FILE`: 日志文件路径(默认: logs/backtest_consumer.log) + ## 9. 系统架构 -### 8.1 组件关系图 +### 9.1 组件关系图 ``` ┌─────────────────────────────────────────────────────────────────────────────┐ @@ -520,7 +517,7 @@ send_qmt_percentage_signal( │ ▼ ▼ ▼ │ │ ┌─────────────┐ ┌─────────────────┐ ┌─────────────────────────┐ │ │ │ 日志系统 │ │ 终端执行单元 │ │ Web 仪表盘 │ │ -│ │ logs/ │ │ TradingUnit │ │ dashboard.html │ │ +│ │ logger.py │ │ TradingUnit │ │ dashboard.html │ │ │ └─────────────┘ │ × N │ │ │ │ │ └────────┬────────┘ └─────────────────────────┘ │ │ │ │ @@ -534,22 +531,22 @@ send_qmt_percentage_signal( │ 外部依赖 │ │ ┌─────────────┐ ┌─────────────────┐ ┌─────────────────────────┐ │ │ │ Redis │ │ QMT 终端 │ │ 浏览器客户端 │ │ -│ │ 消息队列 │ │ 实盘交易 │ │ HTTP 请求 │ │ +│ │ Stream │ │ 实盘交易 │ │ HTTP 请求 │ │ │ └─────────────┘ └─────────────────┘ └─────────────────────────┘ │ └─────────────────────────────────────────────────────────────────────────────┘ ``` -### 8.2 数据流向图 +### 9.2 数据流向图 ``` ┌─────────────────────────────────────────────────────────────────────────────┐ │ 数据流向 │ ├─────────────────────────────────────────────────────────────────────────────┤ │ │ -│ 聚宽策略 ──> qmt_signal_sender ──> Redis 队列 ──> 消息处理循环 │ -│ (信号发送端) {strategy}_real │ │ +│ 聚宽策略 ──> qmt_sender ──> Redis Stream ──> 消息处理循环 │ +│ (信号发送端) qmt:{strategy}:real │ │ │ ▼ │ -│ 槽位检查 ──> 资金检查 │ +│ 槽位/百分比检查 │ │ │ │ │ ▼ │ │ 订单执行 (QMT API) │ @@ -572,20 +569,21 @@ send_qmt_percentage_signal( └─────────────────────────────────────────────────────────────────────────────┘ ``` -### 8.3 消息处理流程 +### 9.3 消息处理流程 -1. **消息接收**:系统从 Redis 队列 `{strategy_name}_real` 中取出消息 +1. **消息接收**:系统从 Redis Stream `qmt:{strategy_name}:real` 中读取消息 2. **消息解析**:将 JSON 消息解析为结构化数据,验证必填字段 3. **日期校验**:检查消息日期是否为当天,过期消息丢弃 -4. **槽位检查**:查询策略已占用槽位,判断是否允许新买入 -5. **资金检查**:查询账户可用资金,计算单只股票可买入金额 +4. **模式检查**:根据策略配置确定使用槽位模式或百分比模式 +5. **槽位/资金检查**:查询策略已占用槽位或账户总资产,判断是否允许新买入 6. **数量计算**:根据资金和价格计算买入股数(向下取整为百股) 7. **订单执行**:调用 QMT API 下单,成功则缓存订单信息 8. **状态更新**:标记虚拟持仓,异步等待成交回调 +9. **消息确认**:发送 ACK 确认消息已处理 ## 10. 启动与停止 -### 9.1 Windows 启动 +### 10.1 Windows 启动 使用提供的 `start.bat` 脚本启动系统: @@ -600,11 +598,11 @@ cd qmt python run.py ``` -### 9.2 日志文件位置 +### 10.2 日志文件位置 系统日志保存在 `qmt/logs/{日期}.log` 目录下,文件名格式为 `2026-01-27.log`。日志按日期自动切分,当日期变化时创建新的日志文件。 -### 9.3 端口说明 +### 10.3 端口说明 | 服务 | 默认端口 | 说明 | |------|----------|------| @@ -617,3 +615,4 @@ python run.py 3. **交易日时间**:交易逻辑仅在 09:15-11:30 和 13:00-15:00 期间执行 4. **维护时段**:每日 21:32-21:50 为 QMT 维护时段,此时段不执行重连 5. **权限要求**:确保程序有权限写入 `logs/` 目录 +6. **配置文件**:Redis 配置优先从 `.env.local` 文件加载,如不存在则使用 `config.json` 中的配置 diff --git a/qmt/qmt_percentage_sender.py b/qmt/qmt_percentage_sender.py deleted file mode 100644 index 1e5d2d7..0000000 --- a/qmt/qmt_percentage_sender.py +++ /dev/null @@ -1,102 +0,0 @@ -import redis -import json - -# --- 模块级全局变量 --- -_BACKTEST_SEND_COUNT = 0 - - -def send_qmt_percentage_signal( - code, position_pct, action, price, is_backtest, timestamp, redis_config -): - """ - 发送基于仓位百分比的信号到 Redis - - 参数: - - code: 股票代码 (聚宽格式: 000001.XSHE) - - position_pct: 目标持仓占总资产的比例 (0.0 ~ 1.0,如 0.2 表示 20%) - - action: 交易动作,"BUY" 或 "SELL" - - price: 当前最新价格 (用于实盘限价单参考) - - is_backtest: 是否为回测模式 (True/False) - - timestamp: 时间戳字符串,格式 "YYYY-MM-DD HH:MM:SS" - - redis_config: Redis配置字典,包含 host, port, password, db, strategy_name - """ - global _BACKTEST_SEND_COUNT - - try: - # --------------------------------------------------------- - # 1. 环境判断与流量控制 - # --------------------------------------------------------- - if is_backtest: - if _BACKTEST_SEND_COUNT >= 10: - return - _BACKTEST_SEND_COUNT += 1 - - # --------------------------------------------------------- - # 2. 建立 Redis 连接 - # --------------------------------------------------------- - r = redis.Redis( - host=redis_config["host"], - port=redis_config["port"], - password=redis_config.get("password"), - db=redis_config.get("db", 0), - decode_responses=True, - socket_timeout=1, - ) - - # --------------------------------------------------------- - # 3. 数据转换与规范化 - # --------------------------------------------------------- - # 股票代码格式转换: 聚宽(.XSHE/.XSHG) -> QMT(.SZ/.SH) - qmt_code = code - if code.endswith(".XSHE"): - qmt_code = code.replace(".XSHE", ".SZ") - elif code.endswith(".XSHG"): - qmt_code = code.replace(".XSHG", ".SH") - - # 校验 action 参数 - if action not in ["BUY", "SELL"]: - print(f"[Error] 无效的 action 参数: {action},必须是 'BUY' 或 'SELL'") - return - - # --------------------------------------------------------- - # 4. 构建消息体 - # --------------------------------------------------------- - base_strategy_name = redis_config.get("strategy_name", "default_strategy") - - msg = { - "strategy_name": base_strategy_name, - "stock_code": qmt_code, - "action": action, - "price": price, - "position_pct": float(position_pct), - "timestamp": timestamp, - "is_backtest": is_backtest, - } - - json_payload = json.dumps(msg) - - # --------------------------------------------------------- - # 5. 队列路由 - # --------------------------------------------------------- - queue_key = ( - f"{base_strategy_name}_backtest" - if is_backtest - else f"{base_strategy_name}_real" - ) - expire_seconds = 3600 if is_backtest else 604800 - - r.rpush(queue_key, json_payload) - r.expire(queue_key, expire_seconds) - - # --------------------------------------------------------- - # 6. 控制台输出 - # --------------------------------------------------------- - log_prefix = "【回测】" if is_backtest else "【实盘】" - pct_display = f"{position_pct * 100:.1f}%" - desc = f"目标仓位:{pct_display}" if action == "BUY" else "清仓" - print( - f"{log_prefix} 百分比信号 -> {qmt_code} | 动作:{action} | {desc} | 价格:{price} | 时间:{timestamp}" - ) - - except Exception as e: - print(f"[Error] 发送QMT百分比信号失败: {e}") diff --git a/qmt/qmt_sender.py b/qmt/qmt_sender.py new file mode 100644 index 0000000..8ae4e33 --- /dev/null +++ b/qmt/qmt_sender.py @@ -0,0 +1,251 @@ +import redis +import json +import socket +import os +from typing import Dict, Any, Optional + +# --- 模块级全局变量 --- +_BACKTEST_SEND_COUNT = 0 + +# --- Stream 配置常量 --- +STREAM_PREFIX = "qmt" +MAXLEN = 1000 # Stream 最大长度 + + +def _get_stream_key(strategy_name: str, is_backtest: bool = False) -> str: + """获取流键名 + + Args: + strategy_name: 策略名称 + is_backtest: 是否为回测模式 + + Returns: + 流键名,格式: qmt:{strategy_name}:real 或 qmt:{strategy_name}:backtest + """ + suffix = "backtest" if is_backtest else "real" + return f"{STREAM_PREFIX}:{strategy_name}:{suffix}" + + +def _create_redis_client(redis_config: Dict[str, Any]) -> redis.Redis: + """创建 Redis 客户端""" + return redis.Redis( + host=redis_config.get("host", "localhost"), + port=redis_config.get("port", 6379), + password=redis_config.get("password"), + db=redis_config.get("db", 0), + decode_responses=True, + socket_timeout=1, + ) + + +def _send_to_stream( + r: redis.Redis, + strategy_name: str, + message_data: Dict[str, Any], + is_backtest: bool = False, +) -> Optional[str]: + """发送消息到 Redis Stream + + Args: + r: Redis 客户端 + strategy_name: 策略名称 + message_data: 消息数据字典 + is_backtest: 是否为回测消息 + + Returns: + 消息ID (格式: timestamp-sequence),失败返回 None + """ + stream_key = _get_stream_key(strategy_name, is_backtest) + + try: + # 确保消息数据是字符串格式 + message_json = json.dumps(message_data, ensure_ascii=False) + + # 使用 XADD 发送消息,设置最大长度 + message_id = r.xadd( + stream_key, + {"data": message_json}, + maxlen=MAXLEN, + approximate=True, # 使用近似裁剪,提高性能 + ) + + return message_id + + except Exception as e: + print(f"[Error] Stream 发送失败: {e}") + return None + + +def _convert_code_to_qmt(code: str) -> str: + """股票代码格式转换: 聚宽(.XSHE/.XSHG) -> QMT(.SZ/.SH)""" + if code.endswith(".XSHE"): + return code.replace(".XSHE", ".SZ") + elif code.endswith(".XSHG"): + return code.replace(".XSHG", ".SH") + return code + + +def send_qmt_signal(code, target_total_slots, price, context, redis_config): + """ + 发送信号到 Redis Stream (基于槽位状态判断买卖意图) + + 参数: + - code: 股票代码 (聚宽格式: 000001.XSHE) + - target_total_slots: + * 意向持仓时: 传入策略设定的总槽位数 (例如 5)。此时 action 判定为 BUY。 + * 意向清仓时: 传入 0。此时 action 判定为 SELL。 + - price: 当前最新价格 (用于实盘限价单参考) + - context: 聚宽上下文对象 + - redis_config: Redis配置字典,包含 host, port, password, db, strategy_name + """ + global _BACKTEST_SEND_COUNT + + try: + # --------------------------------------------------------- + # 1. 环境判断与流量控制 + # --------------------------------------------------------- + run_type = context.run_params.type + is_backtest = run_type in ["simple_backtest", "full_backtest"] + + if is_backtest: + if _BACKTEST_SEND_COUNT >= 10: + print(f"[流量控制] 回测消息已达上限 (10条),跳过发送") + return + _BACKTEST_SEND_COUNT += 1 + + # --------------------------------------------------------- + # 2. 建立 Redis 连接 + # --------------------------------------------------------- + r = _create_redis_client(redis_config) + + # --------------------------------------------------------- + # 3. 数据转换与规范化 + # --------------------------------------------------------- + qmt_code = _convert_code_to_qmt(code) + + # 【核心逻辑】:根据 target_total_slots 判断动作 + if target_total_slots > 0: + action = "BUY" + slots_val = int(target_total_slots) + else: + action = "SELL" + slots_val = 0 + + # --------------------------------------------------------- + # 4. 构建消息体 + # --------------------------------------------------------- + base_strategy_name = redis_config.get("strategy_name", "default_strategy") + ts_str = context.current_dt.strftime("%Y-%m-%d %H:%M:%S") + + msg = { + "strategy_name": base_strategy_name, + "stock_code": qmt_code, + "action": action, + "price": price, + "total_slots": slots_val, + "timestamp": ts_str, + "is_backtest": is_backtest, + } + + # --------------------------------------------------------- + # 5. 使用 Stream 发送消息 + # --------------------------------------------------------- + message_id = _send_to_stream(r, base_strategy_name, msg, is_backtest) + + if message_id: + # --------------------------------------------------------- + # 6. 控制台输出 + # --------------------------------------------------------- + log_prefix = "【回测】" if is_backtest else "【实盘】" + desc = f"目标总持仓:{slots_val}只" if action == "BUY" else "清仓释放槽位" + print( + f"{log_prefix} 信号同步 -> {qmt_code} | 动作:{action} | {desc} | 时间:{ts_str} | msg_id:{message_id}" + ) + else: + print(f"[Error] 发送QMT信号失败: Stream 返回 None") + + except Exception as e: + print(f"[Error] 发送QMT信号失败: {e}") + + +def send_qmt_percentage_signal( + code, position_pct, action, price, is_backtest, timestamp, redis_config +): + """ + 发送基于仓位百分比的信号到 Redis Stream + + 参数: + - code: 股票代码 (聚宽格式: 000001.XSHE) + - position_pct: 目标持仓占总资产的比例 (0.0 ~ 1.0,如 0.2 表示 20%) + - action: 交易动作,"BUY" 或 "SELL" + - price: 当前最新价格 (用于实盘限价单参考) + - is_backtest: 是否为回测模式 (True/False) + - timestamp: 时间戳字符串,格式 "YYYY-MM-DD HH:MM:SS" + - redis_config: Redis配置字典,包含 host, port, password, db, strategy_name + """ + global _BACKTEST_SEND_COUNT + + try: + # --------------------------------------------------------- + # 1. 环境判断与流量控制 + # --------------------------------------------------------- + if is_backtest: + if _BACKTEST_SEND_COUNT >= 10: + return + _BACKTEST_SEND_COUNT += 1 + + # --------------------------------------------------------- + # 2. 建立 Redis 连接 + # --------------------------------------------------------- + r = _create_redis_client(redis_config) + + # --------------------------------------------------------- + # 3. 数据转换与规范化 + # --------------------------------------------------------- + qmt_code = _convert_code_to_qmt(code) + + # 校验 action 参数 + if action not in ["BUY", "SELL"]: + print(f"[Error] 无效的 action 参数: {action},必须是 'BUY' 或 'SELL'") + return + + # --------------------------------------------------------- + # 4. 构建消息体 + # --------------------------------------------------------- + base_strategy_name = redis_config.get("strategy_name", "default_strategy") + + msg = { + "strategy_name": base_strategy_name, + "stock_code": qmt_code, + "action": action, + "price": price, + "position_pct": float(position_pct), + "timestamp": timestamp, + "is_backtest": is_backtest, + } + + # --------------------------------------------------------- + # 5. 使用 Stream 发送消息 + # --------------------------------------------------------- + message_id = _send_to_stream(r, base_strategy_name, msg, is_backtest) + + if message_id: + # --------------------------------------------------------- + # 6. 控制台输出 + # --------------------------------------------------------- + log_prefix = "【回测】" if is_backtest else "【实盘】" + pct_display = f"{position_pct * 100:.1f}%" + desc = f"目标仓位:{pct_display}" if action == "BUY" else "清仓" + print( + f"{log_prefix} 百分比信号 -> {qmt_code} | 动作:{action} | {desc} | 价格:{price} | 时间:{timestamp} | msg_id:{message_id}" + ) + else: + print(f"[Error] 发送QMT百分比信号失败: Stream 返回 None") + + except Exception as e: + print(f"[Error] 发送QMT百分比信号失败: {e}") + + +# 便捷函数别名,保持向后兼容 +send_signal = send_qmt_signal +send_percentage_signal = send_qmt_percentage_signal diff --git a/qmt/qmt_signal_sender.py b/qmt/qmt_signal_sender.py deleted file mode 100644 index eb1fef6..0000000 --- a/qmt/qmt_signal_sender.py +++ /dev/null @@ -1,101 +0,0 @@ -import redis -import json -import datetime - -# --- 模块级全局变量 --- -_BACKTEST_SEND_COUNT = 0 - -def send_qmt_signal(code, target_total_slots, price, context, redis_config): - """ - 发送信号到 Redis (基于槽位状态判断买卖意图) - - 参数: - - code: 股票代码 (聚宽格式: 000001.XSHE) - - target_total_slots: - * 意向持仓时: 传入策略设定的总槽位数 (例如 5)。此时 action 判定为 BUY。 - * 意向清仓时: 传入 0。此时 action 判定为 SELL。 - - price: 当前最新价格 (用于实盘限价单参考) - - context: 聚宽上下文对象 - - redis_config: Redis配置字典 - """ - global _BACKTEST_SEND_COUNT - - try: - # --------------------------------------------------------- - # 1. 环境判断与流量控制 - # --------------------------------------------------------- - run_type = context.run_params.type - is_backtest = run_type in ['simple_backtest', 'full_backtest'] - - if is_backtest: - if _BACKTEST_SEND_COUNT >= 10: - return - _BACKTEST_SEND_COUNT += 1 - - # --------------------------------------------------------- - # 2. 建立 Redis 连接 - # --------------------------------------------------------- - r = redis.Redis( - host=redis_config['host'], - port=redis_config['port'], - password=redis_config.get('password'), - db=redis_config.get('db', 0), - decode_responses=True, - socket_timeout=1 - ) - - # --------------------------------------------------------- - # 3. 数据转换与规范化 - # --------------------------------------------------------- - # 股票代码格式转换: 聚宽(.XSHE/.XSHG) -> QMT(.SZ/.SH) - qmt_code = code - if code.endswith('.XSHE'): - qmt_code = code.replace('.XSHE', '.SZ') - elif code.endswith('.XSHG'): - qmt_code = code.replace('.XSHG', '.SH') - - # 【核心逻辑修改】:根据 target_total_slots 判断动作 - # 不再通过函数名判断,而是看目标状态 - if target_total_slots > 0: - action = 'BUY' - slots_val = int(target_total_slots) # 告知后端:我是基于“N只模型”中的一只 - else: - action = 'SELL' - slots_val = 0 # 清仓 - - # --------------------------------------------------------- - # 4. 构建消息体 - # --------------------------------------------------------- - base_strategy_name = redis_config.get('strategy_name', 'default_strategy') - ts_str = context.current_dt.strftime('%Y-%m-%d %H:%M:%S') - - msg = { - 'strategy_name': base_strategy_name, - 'stock_code': qmt_code, - 'action': action, - 'price': price, - 'total_slots': slots_val, - 'timestamp': ts_str, - 'is_backtest': is_backtest - } - - json_payload = json.dumps(msg) - - # --------------------------------------------------------- - # 5. 队列路由 - # --------------------------------------------------------- - queue_key = f"{base_strategy_name}_backtest" if is_backtest else f"{base_strategy_name}_real" - expire_seconds = 3600 if is_backtest else 604800 - - r.rpush(queue_key, json_payload) - r.expire(queue_key, expire_seconds) - - # --------------------------------------------------------- - # 6. 控制台输出 - # --------------------------------------------------------- - log_prefix = "【回测】" if is_backtest else "【实盘】" - desc = f"目标总持仓:{slots_val}只" if action == 'BUY' else "清仓释放槽位" - print(f"{log_prefix} 信号同步 -> {qmt_code} | 动作:{action} | {desc} | 时间:{ts_str}") - - except Exception as e: - print(f"[Error] 发送QMT信号失败: {e}") \ No newline at end of file diff --git a/qmt/qmt_trader.py b/qmt/qmt_trader.py deleted file mode 100644 index 44ba0c8..0000000 --- a/qmt/qmt_trader.py +++ /dev/null @@ -1,951 +0,0 @@ -# coding:utf-8 -import time, datetime, traceback, sys, json, os, threading -import logging -from typing import Optional -import redis -from xtquant import xtdata -from xtquant.xttrader import XtQuantTrader, XtQuantTraderCallback -from xtquant.xttype import StockAccount -from xtquant import xtconstant - -# FastAPI 相关 -from fastapi import FastAPI -from fastapi.middleware.cors import CORSMiddleware -from fastapi.responses import FileResponse -import uvicorn - -# ================= 0. Windows 防卡死补丁 ================= -try: - import ctypes - - kernel32 = ctypes.windll.kernel32 - # 禁用快速编辑模式 (0x0040) - kernel32.SetConsoleMode(kernel32.GetStdHandle(-10), 128) -except: - pass - - -# ================= 1. 全局状态管理 ================= -class SystemState: - def __init__(self): - self.xt_trader = None - self.acc = None - self.pos_manager = None - self.callback = None - self.is_running = True - self.start_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") - self.last_heartbeat = "Initializing..." - self.config = {} - - # 重连控制 - self.reconnect_attempts: int = 0 # 累计重连次数 - self.max_reconnect_attempts: int = 3 # 最大重连次数 - self.last_reconnect_fail_time: Optional[float] = None # 上次重连失败时间 - - -GLOBAL_STATE = SystemState() -CURRENT_LOG_DATE = None -ORDER_CACHE = {} # 内存缓存: OrderID -> (Strategy, Code, Action) - - -# ================= 2. 增强型日志系统 ================= -def setup_logger(): - global CURRENT_LOG_DATE - log_dir = "logs" - if not os.path.exists(log_dir): - os.makedirs(log_dir) - - today_str = datetime.date.today().strftime("%Y-%m-%d") - CURRENT_LOG_DATE = today_str - log_file = os.path.join(log_dir, f"{today_str}.log") - - logger = logging.getLogger("QMT_Trader") - logger.setLevel(logging.INFO) - - # 清除旧 handler - if logger.handlers: - for handler in logger.handlers[:]: - try: - handler.close() - logger.removeHandler(handler) - except: - pass - - # 格式中增加 线程名,方便排查是 API 线程还是 交易线程 - formatter = logging.Formatter( - "[%(asctime)s] [%(levelname)s] [%(threadName)s] %(message)s", - datefmt="%Y-%m-%d %H:%M:%S", - ) - - # 文件输出 - file_handler = logging.FileHandler(log_file, mode="a", encoding="utf-8") - file_handler.setFormatter(formatter) - - # 控制台输出 (强制刷新流,防止命令行卡住不显示) - stream_handler = logging.StreamHandler(sys.stdout) - stream_handler.setFormatter(formatter) - stream_handler.flush = sys.stdout.flush - - logger.addHandler(file_handler) - logger.addHandler(stream_handler) - return logger - - -logger = setup_logger() - - -# ================= 3. 配置加载 ================= -def load_config(config_file="config.json"): - if getattr(sys, "frozen", False): - base_path = os.path.dirname(sys.executable) - else: - base_path = os.path.dirname(os.path.abspath(__file__)) - full_path = os.path.join(base_path, config_file) - if not os.path.exists(full_path): - if os.path.exists(config_file): - full_path = config_file - else: - logger.error(f"找不到配置文件: {full_path}") - sys.exit(1) - try: - with open(full_path, "r", encoding="utf-8") as f: - return json.load(f) - except Exception as e: - logger.error(f"配置文件错误: {e}") - sys.exit(1) - - -# ================= 4. 业务逻辑类 ================= -class PositionManager: - def __init__(self, r_client): - self.r = r_client - - def _get_key(self, strategy_name): - return f"POS:{strategy_name}" - - def mark_holding(self, strategy_name, code): - self.r.hsetnx(self._get_key(strategy_name), code, 0) - - def rollback_holding(self, strategy_name, code): - key = self._get_key(strategy_name) - val = self.r.hget(key, code) - if val is not None and int(val) == 0: - self.r.hdel(key, code) - logger.warning(f"[{strategy_name}] 回滚释放槽位: {code}") - - def update_actual_volume(self, strategy_name, code, delta_vol): - key = self._get_key(strategy_name) - new_vol = self.r.hincrby(key, code, int(delta_vol)) - if new_vol <= 0: - self.r.hdel(key, code) - new_vol = 0 - return new_vol - - def get_position(self, strategy_name, code): - vol = self.r.hget(self._get_key(strategy_name), code) - return int(vol) if vol else 0 - - def get_holding_count(self, strategy_name): - return self.r.hlen(self._get_key(strategy_name)) - - def get_all_virtual_positions(self, strategy_name): - return self.r.hgetall(self._get_key(strategy_name)) - - def force_delete(self, strategy_name, code): - self.r.hdel(self._get_key(strategy_name), code) - - def clean_stale_placeholders(self, strategy_name, xt_trader, acc): - try: - key = self._get_key(strategy_name) - all_pos = self.r.hgetall(key) - if not all_pos: - return - - active_orders = xt_trader.query_stock_orders(acc, cancelable_only=True) - active_codes = ( - [o.stock_code for o in active_orders] if active_orders else [] - ) - - real_positions = xt_trader.query_stock_positions(acc) - real_holdings = ( - [p.stock_code for p in real_positions if p.volume > 0] - if real_positions - else [] - ) - - for code, vol_str in all_pos.items(): - if int(vol_str) == 0: - if (code not in real_holdings) and (code not in active_codes): - self.r.hdel(key, code) - logger.warning(f"[{strategy_name}] 自动清理僵尸占位: {code}") - except Exception as e: - logger.error(f"清理僵尸占位异常: {e}") - - -class DailySettlement: - def __init__(self, xt_trader, acc, pos_mgr, strategies): - self.trader = xt_trader - self.acc = acc - self.pos_mgr = pos_mgr - self.strategies = strategies - self.has_settled = False - - def run_settlement(self): - logger.info("=" * 40) - logger.info("执行收盘清算流程...") - try: - orders = self.trader.query_stock_orders(self.acc, cancelable_only=True) - logger.info( - f"收盘清算 - 查询可撤单订单: 获取到 {len(orders) if orders else 0} 个订单" - ) - if orders: - for o in orders: - logger.info( - f"收盘清算 - 撤单: OrderID={o.order_id}, Stock={o.stock_code}" - ) - self.trader.cancel_order_stock(self.acc, o.order_id) - time.sleep(2) - logger.info(f"收盘清算 - 完成撤单操作,共处理 {len(orders)} 个订单") - else: - logger.info("收盘清算 - 无待撤单订单") - except Exception as e: - logger.error(f"收盘清算 - 查询/撤单失败: {str(e)}", exc_info=True) - - real_positions = self.trader.query_stock_positions(self.acc) - real_pos_map = ( - {p.stock_code: p.volume for p in real_positions if p.volume > 0} - if real_positions - else {} - ) - - for strategy in self.strategies: - virtual = self.pos_mgr.get_all_virtual_positions(strategy) - for code, v_str in virtual.items(): - v = int(v_str) - if code not in real_pos_map: - logger.warning( - f" [修正] {strategy} 幽灵持仓 {code} (Redis={v}) -> 强制释放" - ) - self.pos_mgr.force_delete(strategy, code) - elif v == 0 and code in real_pos_map: - real_vol = real_pos_map[code] - self.pos_mgr.update_actual_volume(strategy, code, real_vol) - logger.info( - f" [修正] {strategy} 修正占位符 {code} 0 -> {real_vol}" - ) - - logger.info("清算完成") - self.has_settled = True - - def reset_flag(self): - self.has_settled = False - - -class MyXtQuantTraderCallback(XtQuantTraderCallback): - def __init__(self, pos_mgr): - self.pos_mgr = pos_mgr - self.is_connected = False - - def on_disconnected(self): - logger.warning(">> 回调通知: 交易端连接断开") - self.is_connected = False - - def on_stock_trade(self, trade): - try: - cache_info = ORDER_CACHE.get(trade.order_id) - if not cache_info: - return - strategy, _, action = cache_info - logger.info( - f">>> [成交] {strategy} {trade.stock_code} {trade.traded_volume}" - ) - if action == "BUY": - self.pos_mgr.update_actual_volume( - strategy, trade.stock_code, trade.traded_volume - ) - elif action == "SELL": - self.pos_mgr.update_actual_volume( - strategy, trade.stock_code, -trade.traded_volume - ) - except Exception as e: - logger.error(f"on_stock_trade 成交回调处理失败: {str(e)}", exc_info=True) - - def on_order_error(self, err): - try: - logger.error( - f"下单失败回调: OrderID={err.order_id}, 错误信息={err.error_msg}" - ) - cache = ORDER_CACHE.get(err.order_id) - if cache and cache[2] == "BUY": - logger.info(f"回滚持仓: Strategy={cache[0]}, Stock={cache[1]}") - self.pos_mgr.rollback_holding(cache[0], cache[1]) - del ORDER_CACHE[err.order_id] - except Exception as e: - logger.error(f"on_order_error 错误回调处理失败: {str(e)}", exc_info=True) - - -# ================= 5. 核心消息处理 (重写版:拒绝静默失败) ================= -def get_strategy_config(strategy_name, config): - """获取策略配置,支持新旧配置格式兼容""" - strategies = config.get("strategies", {}) - - # 如果 strategies 是列表(旧格式),转换为默认配置 - if isinstance(strategies, list): - return {"order_mode": "slots", "total_slots": 5} - - # 获取策略配置 - strategy_config = strategies.get(strategy_name, {}) - - # 设置默认值 - result = { - "order_mode": strategy_config.get("order_mode", "slots"), - "total_slots": strategy_config.get("total_slots", 5), - } - - return result - - -def process_percentage_buy( - strategy_name, stock_code, price, position_pct, xt_trader, acc -): - """处理百分比模式的买入逻辑""" - logger.info(f"[百分比模式] 处理买入: {stock_code}, 目标占比: {position_pct}") - - # 查询资产 - asset = xt_trader.query_stock_asset(acc) - if not asset: - logger.error("API 错误: query_stock_asset 返回 None,可能是 QMT 断连或未同步") - return - - total_asset = asset.total_asset - available_cash = asset.cash - - logger.info( - f"[百分比模式] 账户总资产: {total_asset:.2f}, 可用资金: {available_cash:.2f}" - ) - - # 计算目标金额 - target_amount = total_asset * position_pct - actual_amount = min(target_amount, available_cash) - - logger.info( - f"[百分比模式] 目标金额: {target_amount:.2f}, 实际可用: {actual_amount:.2f}" - ) - - # 检查最小金额限制 - if actual_amount < 2000: - logger.warning(f"[百分比模式] 拦截买入: 金额过小 ({actual_amount:.2f} < 2000)") - return - - # 价格校验 - if price <= 0: - logger.warning( - f"[百分比模式] 价格异常: {price},强制设为1.0以计算股数(仅测试用)" - ) - price = 1.0 - - # 计算股数 - vol = int(actual_amount / price / 100) * 100 - logger.info( - f"[百分比模式] 计算股数: 资金{actual_amount:.2f} / 价格{price} -> {vol}股" - ) - - if vol < 100: - logger.warning(f"[百分比模式] 拦截买入: 股数不足 100 ({vol})") - return - - # 执行下单 - oid = xt_trader.order_stock( - acc, - stock_code, - xtconstant.STOCK_BUY, - vol, - xtconstant.FIX_PRICE, - price, - strategy_name, - "PyBuyPct", - ) - - if oid != -1: - logger.info(f"[百分比模式] √√√ 下单成功: ID={oid} {stock_code} 买入 {vol}") - ORDER_CACHE[oid] = (strategy_name, stock_code, "BUY") - else: - logger.error( - f"[百分比模式] XXX 下单请求被拒绝 (Result=-1),请检查 QMT 终端报错" - ) - - -def process_percentage_sell(strategy_name, stock_code, price, xt_trader, acc): - """处理百分比模式的卖出逻辑(清仓)""" - logger.info(f"[百分比模式] 处理卖出: {stock_code} (清仓)") - - # 查询实盘持仓 - real_pos = xt_trader.query_stock_positions(acc) - if real_pos is None: - logger.error("[百分比模式] API 错误: query_stock_positions 返回 None") - return - - rp = next((p for p in real_pos if p.stock_code == stock_code), None) - can_use = rp.can_use_volume if rp else 0 - - logger.info(f"[百分比模式] 股票 {stock_code} 实盘可用持仓: {can_use}") - - if can_use <= 0: - logger.warning(f"[百分比模式] 拦截卖出: 无可用持仓") - return - - # 执行清仓 - logger.info(f"[百分比模式] 执行清仓: {stock_code} @ {price}, 数量: {can_use}") - oid = xt_trader.order_stock( - acc, - stock_code, - xtconstant.STOCK_SELL, - can_use, - xtconstant.FIX_PRICE, - price, - strategy_name, - "PySellPct", - ) - - if oid != -1: - logger.info(f"[百分比模式] √√√ 下单成功: ID={oid} {stock_code} 卖出 {can_use}") - ORDER_CACHE[oid] = (strategy_name, stock_code, "SELL") - else: - logger.error(f"[百分比模式] XXX 下单请求被拒绝 (Result=-1)") - - -def process_slots_buy( - strategy_name, stock_code, price, total_slots, xt_trader, acc, pos_manager -): - """处理槽位模式的买入逻辑(原有逻辑保持不变)""" - holding = pos_manager.get_holding_count(strategy_name) - empty = total_slots - holding - - logger.info( - f"[槽位模式] 检查持仓: 当前占用 {holding} / 总槽位 {total_slots} -> 剩余 {empty}" - ) - - if empty <= 0: - logger.warning(f"[槽位模式] 拦截买入: 槽位已满,不执行下单") - return - - # 查询资金 - asset = xt_trader.query_stock_asset(acc) - if not asset: - logger.error( - "[槽位模式] API 错误: query_stock_asset 返回 None,可能是 QMT 断连或未同步" - ) - return - - logger.info(f"[槽位模式] 当前可用资金: {asset.cash:.2f}") - - amt = asset.cash / empty - if amt < 2000: - logger.warning(f"[槽位模式] 拦截买入: 单笔金额过小 ({amt:.2f} < 2000)") - return - - if price <= 0: - logger.warning(f"[槽位模式] 价格异常: {price},强制设为1.0以计算股数(仅测试用)") - price = 1.0 - - vol = int(amt / price / 100) * 100 - logger.info(f"[槽位模式] 计算股数: 资金{amt:.2f} / 价格{price} -> {vol}股") - - if vol < 100: - logger.warning(f"[槽位模式] 拦截买入: 股数不足 100 ({vol})") - return - - # 执行下单 - oid = xt_trader.order_stock( - acc, - stock_code, - xtconstant.STOCK_BUY, - vol, - xtconstant.FIX_PRICE, - price, - strategy_name, - "PyBuy", - ) - - if oid != -1: - logger.info(f"[槽位模式] √√√ 下单成功: ID={oid} {stock_code} 买入 {vol}") - ORDER_CACHE[oid] = (strategy_name, stock_code, "BUY") - pos_manager.mark_holding(strategy_name, stock_code) - else: - logger.error(f"[槽位模式] XXX 下单请求被拒绝 (Result=-1),请检查 QMT 终端报错") - - -def process_slots_sell(strategy_name, stock_code, price, xt_trader, acc, pos_manager): - """处理槽位模式的卖出逻辑(原有逻辑保持不变)""" - v_vol = pos_manager.get_position(strategy_name, stock_code) - logger.info(f"[槽位模式] 卖出 - Redis 记录虚拟持仓: {v_vol}") - - if v_vol > 0: - logger.info(f"[槽位模式] 卖出 - 正在查询实盘持仓: {stock_code}") - real_pos = xt_trader.query_stock_positions(acc) - logger.info( - f"[槽位模式] 卖出 - 实盘持仓查询完成,获取到 {len(real_pos) if real_pos else 0} 条记录" - ) - - if real_pos is None: - logger.error("[槽位模式] API 错误: query_stock_positions 返回 None") - return - - rp = next((p for p in real_pos if p.stock_code == stock_code), None) - can_use = rp.can_use_volume if rp else 0 - logger.info(f"[槽位模式] 卖出 - 股票 {stock_code} 实盘可用持仓: {can_use}") - - final = min(v_vol, can_use) - logger.info(f"[槽位模式] 卖出 - 计算卖出量: min({v_vol}, {can_use}) = {final}") - - if final > 0: - logger.info( - f"[槽位模式] 卖出 - 执行卖出订单: {stock_code} @ {price}, 数量: {final}" - ) - oid = xt_trader.order_stock( - acc, - stock_code, - xtconstant.STOCK_SELL, - final, - xtconstant.FIX_PRICE, - price, - strategy_name, - "PySell", - ) - if oid != -1: - logger.info( - f"[槽位模式] √√√ 下单成功: ID={oid} {stock_code} 卖出 {final}" - ) - ORDER_CACHE[oid] = (strategy_name, stock_code, "SELL") - else: - logger.error(f"[槽位模式] XXX 下单请求被拒绝 (Result=-1)") - else: - logger.warning( - f"[槽位模式] 拦截卖出: 最终计算卖出量为 0 (虚拟:{v_vol}, 实盘:{can_use})" - ) - else: - logger.warning(f"[槽位模式] 拦截卖出: Redis 中无此持仓记录,忽略") - - -def process_strategy_queue( - strategy_name, r_client, xt_trader, acc, pos_manager, config -): - queue_key = f"{strategy_name}_real" - - # 1. 获取消息 - msg_json = r_client.lpop(queue_key) - if not msg_json: - return - - # 2. 存入历史并解析 (打印原始消息,确保知道收到了什么) - logger.info(f"-------- 处理消息 [{strategy_name}] --------") - logger.info(f"收到原始消息: {msg_json}") - - try: - r_client.rpush(f"{queue_key}:history", msg_json) - - try: - data = json.loads(msg_json) - except json.JSONDecodeError: - logger.error("JSON 解析失败,跳过消息") - return - - # 3. 基础校验 (每一步失败都必须打印 Log) - if data.get("is_backtest"): - logger.warning(f"检测到回测标记 is_backtest=True,忽略此消息") - return - - msg_ts = data.get("timestamp") - if not msg_ts: - logger.warning(f"消息缺失时间戳 timestamp,忽略") - return - - today_str = datetime.date.today().strftime("%Y-%m-%d") - msg_date = msg_ts.split(" ")[0] - if msg_date != today_str: - logger.warning(f"消息日期过期: {msg_date} != 今日 {today_str},忽略") - return - - # 4. 提取关键字段 - stock_code = data.get("stock_code") - action = data.get("action") - price = float(data.get("price", 0)) - - if not stock_code or not action: - logger.error(f"缺少关键字段: Code={stock_code}, Action={action}") - return - - # 5. 获取策略配置,确定下单模式 - strategy_config = get_strategy_config(strategy_name, config) - order_mode = strategy_config.get("order_mode", "slots") - - logger.info( - f"解析成功: {action} {stock_code} @ {price}, 下单模式: {order_mode}" - ) - - # 6. QMT 存活检查 - if xt_trader is None or acc is None: - logger.error("严重错误: QMT 对象未初始化 (xt_trader is None)") - return - - # 7. 根据下单模式执行相应逻辑 - if order_mode == "percentage": - # 百分比模式 - position_pct = float(data.get("position_pct", 0)) - - if action == "BUY": - process_percentage_buy( - strategy_name, stock_code, price, position_pct, xt_trader, acc - ) - elif action == "SELL": - process_percentage_sell( - strategy_name, stock_code, price, xt_trader, acc - ) - else: - logger.error(f"未知的 Action: {action}") - - else: - # 槽位模式(默认) - total_slots = int( - data.get("total_slots", strategy_config.get("total_slots", 5)) - ) - - if action == "BUY": - process_slots_buy( - strategy_name, - stock_code, - price, - total_slots, - xt_trader, - acc, - pos_manager, - ) - elif action == "SELL": - process_slots_sell( - strategy_name, stock_code, price, xt_trader, acc, pos_manager - ) - else: - logger.error(f"未知的 Action: {action}") - - except Exception as e: - logger.error(f"消息处理发生未捕获异常: {str(e)}", exc_info=True) - - -# ================= 6. QMT初始化 ================= -def init_qmt_trader(qmt_path, account_id, account_type, pos_manager): - try: - session_id = int(time.time()) - logger.info(f"正在连接 QMT (Path: {qmt_path})...") - trader = XtQuantTrader(qmt_path, session_id) - acc = StockAccount(account_id, account_type) - callback = MyXtQuantTraderCallback(pos_manager) - trader.register_callback(callback) - trader.start() - res = trader.connect() - if res == 0: - logger.info(f"QMT 连接成功 [Session:{session_id}]") - trader.subscribe(acc) - callback.is_connected = True - return trader, acc, callback - else: - logger.error(f"QMT 连接失败 Code:{res} (请检查 QMT 是否登录且路径正确)") - return None, None, None - except Exception as e: - logger.error(f"初始化异常: {e}", exc_info=True) - return None, None, None - - -# ================= 7. 交易逻辑主循环 ================= -def trading_loop(): - global logger - threading.current_thread().name = "TradeThread" - logger.info(">>> 交易逻辑子线程启动 <<<") - - GLOBAL_STATE.config = load_config("config.json") - CONFIG = GLOBAL_STATE.config - redis_cfg = CONFIG["redis"] - qmt_cfg = CONFIG["qmt"] - watch_list = CONFIG["strategies"] - - try: - r = redis.Redis(**redis_cfg, decode_responses=True) - r.ping() - pos_manager = PositionManager(r) - GLOBAL_STATE.pos_manager = pos_manager - logger.info("Redis 连接成功") - except Exception as e: - logger.critical(f"Redis 连接失败: {e}") - return - - # 初始化 - xt_trader, acc, callback = init_qmt_trader( - qmt_cfg["path"], qmt_cfg["account_id"], qmt_cfg["account_type"], pos_manager - ) - GLOBAL_STATE.xt_trader = xt_trader - GLOBAL_STATE.acc = acc - GLOBAL_STATE.callback = callback - - settler = None - if xt_trader: - settler = DailySettlement(xt_trader, acc, pos_manager, watch_list) - for s in watch_list: - pos_manager.clean_stale_placeholders(s, xt_trader, acc) - - logger.info(">>> 进入主轮询循环 <<<") - - last_health_check = 0 # 上次深度检查时间 - - while GLOBAL_STATE.is_running: - try: - # 1. 基础心跳更新 - GLOBAL_STATE.last_heartbeat = datetime.datetime.now().strftime("%H:%M:%S") - - # 2. 状态诊断与自动修复 (关键修改!!!) - # 每 15 秒执行一次“深度探测”,而不是每一轮都看 callback - if time.time() - last_health_check > 15: - last_health_check = time.time() - - is_alive_physically = False - - # 尝试通过“查资产”来验证连接是否真的活着 - if GLOBAL_STATE.xt_trader and GLOBAL_STATE.acc: - try: - asset = GLOBAL_STATE.xt_trader.query_stock_asset( - GLOBAL_STATE.acc - ) - if asset: - is_alive_physically = True - # 【核心修复】:如果物理探测成功,强行修正 callback 状态 - if ( - GLOBAL_STATE.callback - and not GLOBAL_STATE.callback.is_connected - ): - GLOBAL_STATE.callback.is_connected = True - logger.info( - "✅ [自愈] 检测到资产查询正常,修正伪造的断开状态 (False -> True)" - ) - except Exception as e: - logger.warning(f"[健康检查] 资产查询失败: {str(e)}") - - # 只有当 逻辑断开(callback) AND 物理断开(无法查资产) 时,才判定为断线 - current_status = ( - GLOBAL_STATE.callback.is_connected - if GLOBAL_STATE.callback - else False - ) - - # 减少日志刷屏:只有状态真的异常时才打印 - if not current_status and not is_alive_physically: - logger.warning( - f"⚠️ 线程存活检查 | 逻辑状态:{current_status} | 物理探测:失败" - ) - - # 3. 断线重连逻辑 - # 只有"物理探测"彻底失败了,才执行重连 - if not is_alive_physically: - # 避让 QMT 夜间重启高峰期 (23:20 - 23:35) - # 避免在这段时间疯狂重连打印日志 - now_hm = datetime.datetime.now().strftime("%H%M") - if "2320" <= now_hm <= "2335": - logger.info("⏳ QMT维护时段,暂停重连,休眠60秒...") - time.sleep(60) - continue - - if datetime.date.today().weekday() >= 5: # 周末 - time.sleep(3600) - continue - - # 检查重连次数是否超过限制 - if ( - GLOBAL_STATE.reconnect_attempts - >= GLOBAL_STATE.max_reconnect_attempts - ): - logger.warning( - f"⚠️ 重连失败次数已达上限 ({GLOBAL_STATE.reconnect_attempts}/{GLOBAL_STATE.max_reconnect_attempts}),停止自动重连" - ) - # 如果距离上次失败超过5分钟,重置计数器 - if GLOBAL_STATE.last_reconnect_fail_time: - elapsed = ( - time.time() - GLOBAL_STATE.last_reconnect_fail_time - ) - if elapsed > 300: # 5分钟 - GLOBAL_STATE.reconnect_attempts = 0 - logger.info( - f"⏰ 重连计数器已重置 (距离上次失败 {elapsed / 60:.1f} 分钟)" - ) - else: - logger.info(f"⏳ 需要等待 {300 - elapsed:.0f} 秒后重试") - # 在重连次数超限时,仍然等待一段时间再继续循环 - time.sleep(60) - continue - - logger.warning( - f"🚫 确认连接丢失,执行重连 ({GLOBAL_STATE.reconnect_attempts + 1}/{GLOBAL_STATE.max_reconnect_attempts})..." - ) - if GLOBAL_STATE.xt_trader: - try: - GLOBAL_STATE.xt_trader.stop() - logger.info("已停止旧交易实例") - except Exception as e: - logger.error(f"停止旧交易实例失败: {str(e)}", exc_info=True) - - new_trader, new_acc, new_cb = init_qmt_trader( - qmt_cfg["path"], - qmt_cfg["account_id"], - qmt_cfg["account_type"], - pos_manager, - ) - - if new_trader: - GLOBAL_STATE.xt_trader = new_trader - GLOBAL_STATE.acc = new_acc - GLOBAL_STATE.callback = new_cb - GLOBAL_STATE.reconnect_attempts = 0 # 重连成功后重置计数 - GLOBAL_STATE.last_reconnect_fail_time = None - settler = DailySettlement( - new_trader, new_acc, pos_manager, watch_list - ) - logger.info("✅ 重连成功") - else: - GLOBAL_STATE.reconnect_attempts += 1 - GLOBAL_STATE.last_reconnect_fail_time = time.time() - logger.error( - f"❌ 重连失败,已尝试 {GLOBAL_STATE.reconnect_attempts}/{GLOBAL_STATE.max_reconnect_attempts} 次,60秒后重试" - ) - time.sleep(60) - continue - - # 4. 日志轮转与心跳文件 - today_str = datetime.date.today().strftime("%Y-%m-%d") - if today_str != CURRENT_LOG_DATE: - logger = setup_logger() - - try: - with open("heartbeat.txt", "w") as f: - f.write(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")) - except Exception as e: - logger.warning(f"[心跳] 写入心跳文件失败: {str(e)}") - - # 5. 交易逻辑处理 - current_time_str = datetime.datetime.now().strftime("%H%M%S") - is_trading_time = ("091500" <= current_time_str <= "113000") or ( - "130000" <= current_time_str <= "150000" - ) - - # 如果连接正常(无论 callback 怎么说,只要上面探测过了,xt_trader 就是可用的) - if is_trading_time and GLOBAL_STATE.xt_trader: - if settler and settler.has_settled: - settler.reset_flag() - for s in watch_list: - process_strategy_queue( - s, - r, - GLOBAL_STATE.xt_trader, - GLOBAL_STATE.acc, - pos_manager, - CONFIG, - ) - - elif "150500" <= current_time_str <= "151000": - if settler and not settler.has_settled: - settler.run_settlement() - - time.sleep(1 if is_trading_time else 5) - - except Exception as e: - logger.critical("交易循环异常", exc_info=True) - time.sleep(10) - - -# ================= 8. FastAPI 接口 ================= -app = FastAPI(title="QMT Monitor") - -app.add_middleware( - CORSMiddleware, - allow_origins=["*"], - allow_methods=["*"], - allow_headers=["*"], -) - - -@app.get("/") -async def read_root(): - if os.path.exists("dashboard.html"): - return FileResponse("dashboard.html") - return {"error": "Dashboard not found"} - - -@app.get("/api/status") -def get_status(): - connected = False - if GLOBAL_STATE.callback: - connected = GLOBAL_STATE.callback.is_connected - return { - "running": True, - "qmt_connected": connected, - "start_time": GLOBAL_STATE.start_time, - "last_loop_update": GLOBAL_STATE.last_heartbeat, - "account_id": GLOBAL_STATE.acc.account_id if GLOBAL_STATE.acc else "Unknown", - } - - -@app.get("/api/positions") -def get_positions(): - real_pos_list = [] - virtual_pos_map = {} - - if ( - GLOBAL_STATE.xt_trader - and GLOBAL_STATE.acc - and GLOBAL_STATE.callback - and GLOBAL_STATE.callback.is_connected - ): - try: - positions = GLOBAL_STATE.xt_trader.query_stock_positions(GLOBAL_STATE.acc) - if positions: - for p in positions: - if p.volume > 0: - real_pos_list.append( - { - "code": p.stock_code, - "volume": p.volume, - "can_use": p.can_use_volume, - "market_value": p.market_value, - } - ) - except Exception as e: - logger.warning(f"[API] 查询持仓失败: {str(e)}") - - if GLOBAL_STATE.config and GLOBAL_STATE.pos_manager: - for s in GLOBAL_STATE.config.get("strategies", []): - v_data = GLOBAL_STATE.pos_manager.get_all_virtual_positions(s) - virtual_pos_map[s] = v_data - - return {"real_positions": real_pos_list, "virtual_positions": virtual_pos_map} - - -@app.get("/api/logs") -def get_logs(lines: int = 50): - today_str = datetime.date.today().strftime("%Y-%m-%d") - log_path = os.path.join("logs", f"{today_str}.log") - if not os.path.exists(log_path): - return {"logs": ["暂无今日日志"]} - try: - with open(log_path, "r", encoding="utf-8") as f: - all_lines = f.readlines() - return {"logs": [line.strip() for line in all_lines[-lines:]]} - except Exception as e: - return {"logs": [f"读取失败: {str(e)}"]} - - -# ================= 9. 启动入口 ================= -if __name__ == "__main__": - # 使用 -u 参数运行是最佳实践: python -u main.py - # 但这里也在代码里强制 flush 了 - print(">>> 系统正在启动...") - - t = threading.Thread(target=trading_loop, daemon=True) - t.start() - - print("Web服务启动: http://localhost:8001") - uvicorn.run(app, host="0.0.0.0", port=8001, log_level="warning")