diff --git a/backend/service_implementation/qihuo_analyzer/data/__pycache__/data_fetcher.cpython-311.pyc b/backend/service_implementation/qihuo_analyzer/data/__pycache__/data_fetcher.cpython-311.pyc index 097dd0a..d4ab71b 100644 Binary files a/backend/service_implementation/qihuo_analyzer/data/__pycache__/data_fetcher.cpython-311.pyc and b/backend/service_implementation/qihuo_analyzer/data/__pycache__/data_fetcher.cpython-311.pyc differ diff --git a/backend/service_implementation/qihuo_analyzer/data/api_adapters/__pycache__/tqsdk_adapter.cpython-311.pyc b/backend/service_implementation/qihuo_analyzer/data/api_adapters/__pycache__/tqsdk_adapter.cpython-311.pyc index 22179d5..b32ae97 100644 Binary files a/backend/service_implementation/qihuo_analyzer/data/api_adapters/__pycache__/tqsdk_adapter.cpython-311.pyc and b/backend/service_implementation/qihuo_analyzer/data/api_adapters/__pycache__/tqsdk_adapter.cpython-311.pyc differ diff --git a/backend/service_implementation/qihuo_analyzer/data/api_adapters/tqsdk_adapter.py b/backend/service_implementation/qihuo_analyzer/data/api_adapters/tqsdk_adapter.py index 06ad9e8..86e86e8 100644 --- a/backend/service_implementation/qihuo_analyzer/data/api_adapters/tqsdk_adapter.py +++ b/backend/service_implementation/qihuo_analyzer/data/api_adapters/tqsdk_adapter.py @@ -324,6 +324,75 @@ class TqSdkAdapter(BaseDataAdapter): print(f"获取所有品种列表失败:{e}") return self._get_mock_all_symbols() + def get_main_contracts(self) -> Dict[str, str]: + """获取主力合约 + + Returns: + Dict[str, str]: 品种代码到主力合约代码的映射 + """ + try: + if TQSDK_AVAILABLE and self.api: + # 使用TQSDK的query_quotes方法获取主力合约 + main_contracts = {} + + # 尝试获取不同类别的主力合约 + for ins_class in ['FUTURE']: + try: + # 查询主力合约 + quotes = self.api.query_quotes(ins_class=ins_class) + + # 等待数据准备就绪 + import time + start_time = time.time() + timeout = 5 # 5秒超时 + + while True: + if quotes: + break + if time.time() - start_time > timeout: + print("获取主力合约数据超时") + break + time.sleep(0.1) + + # 处理获取到的主力合约 + for quote in quotes: + try: + # 获取合约信息 + contract_info = self.api.get_quote(quote) + self.api.wait_update() + + if hasattr(contract_info, 'underlying_symbol') and hasattr(contract_info, 'instrument_id'): + underlying_symbol = contract_info.underlying_symbol + instrument_id = contract_info.instrument_id + main_contracts[underlying_symbol] = instrument_id + except Exception as e: + print(f"处理主力合约 {quote} 失败:{e}") + except Exception as e: + print(f"获取 {ins_class} 类别的主力合约失败:{e}") + + print(f"获取到主力合约:{main_contracts}") + return main_contracts + else: + # 返回模拟数据 + print("无法获取真实主力合约数据,使用模拟数据") + return self._get_mock_main_contracts() + except Exception as e: + print(f"获取主力合约失败:{e}") + return self._get_mock_main_contracts() + + def _get_mock_main_contracts(self) -> Dict[str, str]: + """获取模拟主力合约数据""" + # 模拟主力合约数据 + mock_main_contracts = { + 'AU': 'AU2603', # 黄金 + 'AG': 'AG2603', # 白银 + 'CU': 'CU2603', # 铜 + 'NI': 'NI2603', # 镍 + 'SN': 'SN2603' # 锡 + } + print(f"使用模拟主力合约数据: {mock_main_contracts}") + return mock_main_contracts + def _get_mock_all_symbols(self) -> List[str]: """获取模拟品种列表""" # 返回exchange_map中映射的所有品种 diff --git a/backend/service_implementation/qihuo_analyzer/data/data_fetcher.py b/backend/service_implementation/qihuo_analyzer/data/data_fetcher.py index 3a35b76..0dd3543 100644 --- a/backend/service_implementation/qihuo_analyzer/data/data_fetcher.py +++ b/backend/service_implementation/qihuo_analyzer/data/data_fetcher.py @@ -433,6 +433,36 @@ class DataFetcher: {'symbol': 'AL2603', 'product': 'AL', 'product_name': '铝', 'exchange': 'SHFE', 'month': '2603'}, {'symbol': 'ZN2603', 'product': 'ZN', 'product_name': '锌', 'exchange': 'SHFE', 'month': '2603'} ] + + def get_main_contracts(self) -> Dict[str, str]: + """获取主力合约 + + Returns: + Dict[str, str]: 品种代码到主力合约代码的映射 + """ + try: + # 使用适配器的get_main_contracts方法 + result = self.adapter.get_main_contracts() + if result: + return result + else: + # 如果适配器返回空,使用模拟数据 + print("使用模拟主力合约数据") + return self._get_mock_main_contracts() + except Exception as e: + print(f"获取主力合约失败:{e}") + return self._get_mock_main_contracts() + + def _get_mock_main_contracts(self) -> Dict[str, str]: + """获取模拟主力合约数据""" + # 模拟主力合约数据 + return { + 'AU': 'AU2603', # 黄金 + 'AG': 'AG2603', # 白银 + 'CU': 'CU2603', # 铜 + 'NI': 'NI2603', # 镍 + 'SN': 'SN2603' # 锡 + } # 导入numpy diff --git a/backend/service_implementation/service/app.py b/backend/service_implementation/service/app.py index 6407599..dc3b923 100644 --- a/backend/service_implementation/service/app.py +++ b/backend/service_implementation/service/app.py @@ -46,6 +46,28 @@ def get_contracts(): except Exception as e: return jsonify({'status': 'error', 'message': str(e)}), 500 +# 主力合约获取接口 +@app.route('/api/main-contracts', methods=['GET']) +def get_main_contracts(): + try: + print("正在获取主力合约数据...") + main_contracts = data_fetcher.get_main_contracts() + print(f"获取到主力合约:{main_contracts}") + + # 转换为主力合约列表格式,包含品种名称 + main_contracts_list = [] + for product, contract in main_contracts.items(): + product_name = data_fetcher.get_product_name_cn(product) + main_contracts_list.append({ + 'product': product, + 'product_name': product_name, + 'main_contract': contract + }) + + return jsonify({'status': 'success', 'data': main_contracts_list}) + except Exception as e: + return jsonify({'status': 'error', 'message': str(e)}), 500 + # K线数据获取接口 @app.route('/api/kline', methods=['GET']) def get_kline(): diff --git a/backend/service_implementation/service/data/futures_analysis.db b/backend/service_implementation/service/data/futures_analysis.db index 13a0ef9..46d4822 100644 Binary files a/backend/service_implementation/service/data/futures_analysis.db and b/backend/service_implementation/service/data/futures_analysis.db differ diff --git a/docs/开发文档/合约数据获取逻辑.md b/docs/开发文档/合约数据获取逻辑.md index 3d32fb1..9c6bd9d 100644 --- a/docs/开发文档/合约数据获取逻辑.md +++ b/docs/开发文档/合约数据获取逻辑.md @@ -73,10 +73,67 @@ 7. 处理数据并返回给客户端 8. 如果TQSDK失败,自动切换到测试数据源 +## 主力合约获取 + +### 核心流程 + +1. **主力合约获取机制**: + - 系统通过TQSDK的`query_quotes()`方法获取主力合约数据 + - 支持实盘数据和模拟数据两种模式 + - 实现了异常处理和超时机制,确保获取过程稳定 + +2. **数据处理**: + - 从TQSDK获取主力合约列表 + - 提取品种代码和对应的主力合约代码 + - 转换为主力合约映射表,便于查询 + +3. **API接口**: + - 提供`/api/main-contracts`接口,返回主力合约数据 + - 接口返回格式包含品种代码、品种名称和主力合约代码 + +### 代码位置 + +- **TQSDK适配器**:`backend/service_implementation/qihuo_analyzer/data/api_adapters/tqsdk_adapter.py` + - 实现了`get_main_contracts()`方法,使用TQSDK获取主力合约数据 + - 提供了模拟数据作为fallback + +- **数据获取器**:`backend/service_implementation/qihuo_analyzer/data/data_fetcher.py` + - 实现了`get_main_contracts()`方法,作为适配器方法的包装 + - 提供了统一的主力合约获取接口 + +- **API服务**:`backend/service_implementation/service/app.py` + - 添加了`/api/main-contracts`接口,返回主力合约数据 + - 处理数据格式转换和错误处理 + +### 使用方法 + +1. **通过API接口获取**: + ``` + GET http://localhost:5000/api/main-contracts + ``` + +2. **在代码中获取**: + ```python + from qihuo_analyzer.data.data_fetcher import DataFetcher + + data_fetcher = DataFetcher() + data_fetcher.connect() + main_contracts = data_fetcher.get_main_contracts() + print(main_contracts) # 输出:{'AU': 'AU2603', 'AG': 'AG2603', ...} + ``` + +### 技术实现细节 + +- **TQSDK接口**:使用`query_quotes(ins_class='FUTURE')`获取主力合约数据 +- **数据处理**:通过`get_quote()`获取合约详细信息,提取`underlying_symbol`和`instrument_id` +- **异常处理**:实现了多层异常捕获,确保系统稳定性 +- **模拟数据**:当TQSDK不可用时,使用预定义的模拟数据 + ## 技术特点 1. **工厂模式**:使用工厂模式管理数据源实例,提高代码可维护性 2. **接口隔离**:通过接口定义数据源行为,便于扩展新的数据源类型 3. **容错机制**:实现了数据源故障自动切换,提高系统可靠性 4. **配置驱动**:数据源配置通过配置文件管理,便于运维和部署 -5. **模块化设计**:将数据获取逻辑与API接口分离,提高代码可读性 \ No newline at end of file +5. **模块化设计**:将数据获取逻辑与API接口分离,提高代码可读性 +6. **主力合约支持**:实现了主力合约的自动获取和管理,方便用户快速访问主要交易合约 \ No newline at end of file