real-time-stock-mcp-service 1.1.2__tar.gz → 1.2.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {real_time_stock_mcp_service-1.1.2 → real_time_stock_mcp_service-1.2.1}/PKG-INFO +5 -5
- {real_time_stock_mcp_service-1.1.2 → real_time_stock_mcp_service-1.2.1}/README.md +4 -4
- {real_time_stock_mcp_service-1.1.2 → real_time_stock_mcp_service-1.2.1}/pyproject.toml +1 -1
- {real_time_stock_mcp_service-1.1.2 → real_time_stock_mcp_service-1.2.1}/src/stock_mcp/crawler/technical_data.py +30 -0
- real_time_stock_mcp_service-1.2.1/src/stock_mcp/crawler/test.py +5 -0
- {real_time_stock_mcp_service-1.1.2 → real_time_stock_mcp_service-1.2.1}/src/stock_mcp/crawler/test_count_changes.py +1 -1
- {real_time_stock_mcp_service-1.1.2 → real_time_stock_mcp_service-1.2.1}/src/stock_mcp/data_source_interface.py +17 -6
- {real_time_stock_mcp_service-1.1.2 → real_time_stock_mcp_service-1.2.1}/src/stock_mcp/mcp_tools/kline_data.py +104 -1
- {real_time_stock_mcp_service-1.1.2 → real_time_stock_mcp_service-1.2.1}/src/stock_mcp/stock_data_source.py +4 -1
- real_time_stock_mcp_service-1.1.2/src/stock_mcp/crawler/test.py +0 -16
- {real_time_stock_mcp_service-1.1.2 → real_time_stock_mcp_service-1.2.1}/.gitignore +0 -0
- {real_time_stock_mcp_service-1.1.2 → real_time_stock_mcp_service-1.2.1}/LICENSE +0 -0
- {real_time_stock_mcp_service-1.1.2 → real_time_stock_mcp_service-1.2.1}/src/stock_mcp/__init__.py +0 -0
- {real_time_stock_mcp_service-1.1.2 → real_time_stock_mcp_service-1.2.1}/src/stock_mcp/__main__.py +0 -0
- {real_time_stock_mcp_service-1.1.2 → real_time_stock_mcp_service-1.2.1}/src/stock_mcp/app.py +0 -0
- {real_time_stock_mcp_service-1.1.2 → real_time_stock_mcp_service-1.2.1}/src/stock_mcp/crawler/__init__.py +0 -0
- {real_time_stock_mcp_service-1.1.2 → real_time_stock_mcp_service-1.2.1}/src/stock_mcp/crawler/base_crawler.py +0 -0
- {real_time_stock_mcp_service-1.1.2 → real_time_stock_mcp_service-1.2.1}/src/stock_mcp/crawler/basic_data.py +0 -0
- {real_time_stock_mcp_service-1.1.2 → real_time_stock_mcp_service-1.2.1}/src/stock_mcp/crawler/financial_analysis.py +0 -0
- {real_time_stock_mcp_service-1.1.2 → real_time_stock_mcp_service-1.2.1}/src/stock_mcp/crawler/fundamental_data.py +0 -0
- {real_time_stock_mcp_service-1.1.2 → real_time_stock_mcp_service-1.2.1}/src/stock_mcp/crawler/market.py +0 -0
- {real_time_stock_mcp_service-1.1.2 → real_time_stock_mcp_service-1.2.1}/src/stock_mcp/crawler/real_time_data.py +0 -0
- {real_time_stock_mcp_service-1.1.2 → real_time_stock_mcp_service-1.2.1}/src/stock_mcp/crawler/smart_review.py +0 -0
- {real_time_stock_mcp_service-1.1.2 → real_time_stock_mcp_service-1.2.1}/src/stock_mcp/crawler/valuation_data.py +0 -0
- {real_time_stock_mcp_service-1.1.2 → real_time_stock_mcp_service-1.2.1}/src/stock_mcp/mcp_tools/__init__.py +0 -0
- {real_time_stock_mcp_service-1.1.2 → real_time_stock_mcp_service-1.2.1}/src/stock_mcp/mcp_tools/financial_analysis.py +0 -0
- {real_time_stock_mcp_service-1.1.2 → real_time_stock_mcp_service-1.2.1}/src/stock_mcp/mcp_tools/fundamental.py +0 -0
- {real_time_stock_mcp_service-1.1.2 → real_time_stock_mcp_service-1.2.1}/src/stock_mcp/mcp_tools/market.py +0 -0
- {real_time_stock_mcp_service-1.1.2 → real_time_stock_mcp_service-1.2.1}/src/stock_mcp/mcp_tools/real_time_data.py +0 -0
- {real_time_stock_mcp_service-1.1.2 → real_time_stock_mcp_service-1.2.1}/src/stock_mcp/mcp_tools/search.py +0 -0
- {real_time_stock_mcp_service-1.1.2 → real_time_stock_mcp_service-1.2.1}/src/stock_mcp/mcp_tools/smart_review.py +0 -0
- {real_time_stock_mcp_service-1.1.2 → real_time_stock_mcp_service-1.2.1}/src/stock_mcp/mcp_tools/valuation.py +0 -0
- {real_time_stock_mcp_service-1.1.2 → real_time_stock_mcp_service-1.2.1}/src/stock_mcp/utils/__init__.py +0 -0
- {real_time_stock_mcp_service-1.1.2 → real_time_stock_mcp_service-1.2.1}/src/stock_mcp/utils/markdown_formatter.py +0 -0
- {real_time_stock_mcp_service-1.1.2 → real_time_stock_mcp_service-1.2.1}/src/stock_mcp/utils/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: real-time-stock-mcp-service
|
|
3
|
-
Version: 1.1
|
|
3
|
+
Version: 1.2.1
|
|
4
4
|
Summary: 一个获取实时股票数据服务和分析的MCP服务器
|
|
5
5
|
License-File: LICENSE
|
|
6
6
|
Requires-Python: >=3.12
|
|
@@ -24,15 +24,15 @@ Description-Content-Type: text/markdown
|
|
|
24
24
|
## 功能特性
|
|
25
25
|
|
|
26
26
|
- 📊 查找股票
|
|
27
|
-
- 📈 K线数据查询(支持B股,H
|
|
28
|
-
- 📉 技术指标分析 (MA,MACD,BOLL,
|
|
27
|
+
- 📈 K线数据查询(支持B股,H股,大盘,分时图)
|
|
28
|
+
- 📉 技术指标分析 (MA,MACD,BOLL,RSI等等)
|
|
29
29
|
- 💰 基本面数据分析(主营构成、经营范围等)
|
|
30
30
|
- 📊 财务分析(财务比率、业绩概况等)
|
|
31
31
|
- 💰 估值分析数据(市盈率、市净率等)
|
|
32
32
|
- 📈 市场行情跟踪(板块行情、同行对比、资金流向等)
|
|
33
33
|
- 🤖 智能点评和评分
|
|
34
34
|
|
|
35
|
-
共
|
|
35
|
+
共34个MCP工具
|
|
36
36
|
|
|
37
37
|
## 使用方法
|
|
38
38
|
|
|
@@ -92,7 +92,7 @@ https://modelscope.cn/mcp/servers/DannyWong/real-time-stock-mcp
|
|
|
92
92
|
|
|
93
93
|
## 工具模块
|
|
94
94
|
|
|
95
|
-
项目包含
|
|
95
|
+
项目包含34个MCP工具模块,每个模块提供特定领域的功能:
|
|
96
96
|
|
|
97
97
|
- `search.py` - 股票搜索和交易日信息
|
|
98
98
|
- `real_time_data.py` - 实时股票行情数据
|
|
@@ -12,15 +12,15 @@
|
|
|
12
12
|
## 功能特性
|
|
13
13
|
|
|
14
14
|
- 📊 查找股票
|
|
15
|
-
- 📈 K线数据查询(支持B股,H
|
|
16
|
-
- 📉 技术指标分析 (MA,MACD,BOLL,
|
|
15
|
+
- 📈 K线数据查询(支持B股,H股,大盘,分时图)
|
|
16
|
+
- 📉 技术指标分析 (MA,MACD,BOLL,RSI等等)
|
|
17
17
|
- 💰 基本面数据分析(主营构成、经营范围等)
|
|
18
18
|
- 📊 财务分析(财务比率、业绩概况等)
|
|
19
19
|
- 💰 估值分析数据(市盈率、市净率等)
|
|
20
20
|
- 📈 市场行情跟踪(板块行情、同行对比、资金流向等)
|
|
21
21
|
- 🤖 智能点评和评分
|
|
22
22
|
|
|
23
|
-
共
|
|
23
|
+
共34个MCP工具
|
|
24
24
|
|
|
25
25
|
## 使用方法
|
|
26
26
|
|
|
@@ -80,7 +80,7 @@ https://modelscope.cn/mcp/servers/DannyWong/real-time-stock-mcp
|
|
|
80
80
|
|
|
81
81
|
## 工具模块
|
|
82
82
|
|
|
83
|
-
项目包含
|
|
83
|
+
项目包含34个MCP工具模块,每个模块提供特定领域的功能:
|
|
84
84
|
|
|
85
85
|
- `search.py` - 股票搜索和交易日信息
|
|
86
86
|
- `real_time_data.py` - 实时股票行情数据
|
|
@@ -14,6 +14,7 @@ class KlineSpider(EastMoneyBaseSpider):
|
|
|
14
14
|
|
|
15
15
|
BASE_URL = "https://push2his.eastmoney.com/api/qt/stock/kline/get"
|
|
16
16
|
TECHNICAL_INDICATORS_URL = "https://datacenter-web.eastmoney.com/api/data/v1/get"
|
|
17
|
+
PKYD_URL = "https://push2.eastmoney.com/api/qt/pkyd/get" # 盘口异动API
|
|
17
18
|
|
|
18
19
|
# K线周期常量
|
|
19
20
|
KLT_1MIN = 1
|
|
@@ -108,6 +109,35 @@ class KlineSpider(EastMoneyBaseSpider):
|
|
|
108
109
|
|
|
109
110
|
return merged_data
|
|
110
111
|
|
|
112
|
+
def get_intraday_changes(self, stock_code: str) -> List[str]:
|
|
113
|
+
"""
|
|
114
|
+
获取分时图盘口异动数据
|
|
115
|
+
|
|
116
|
+
:param stock_code: 股票代码,如"300274.SZ"
|
|
117
|
+
:return: 盘口异动数据列表
|
|
118
|
+
"""
|
|
119
|
+
secid = self.format_secid(stock_code)
|
|
120
|
+
|
|
121
|
+
params = {
|
|
122
|
+
"fields": "f1,f2,f3,f4,f5,f6,f7",
|
|
123
|
+
"secids": secid,
|
|
124
|
+
"lmt": "40",
|
|
125
|
+
"ut": "fa5fd1943c7b386f172d6893dbfba10b",
|
|
126
|
+
"wbp2u": "1849325530509956|0|1|0|web",
|
|
127
|
+
"cb": "quote_jp0"
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
response = self._get_jsonp(self.PKYD_URL, params)
|
|
131
|
+
|
|
132
|
+
if not response or not response.get("data"):
|
|
133
|
+
raise RuntimeError(f"获取盘口异动数据失败: {response}")
|
|
134
|
+
|
|
135
|
+
pkyd_data = response["data"].get("pkyd")
|
|
136
|
+
if pkyd_data is None:
|
|
137
|
+
raise RuntimeError(f"响应无 pkyd 字段: {response}")
|
|
138
|
+
|
|
139
|
+
return pkyd_data
|
|
140
|
+
|
|
111
141
|
def _get_macd_data(self, stock_code: str, page_size: int) -> List[Dict[Any, Any]]:
|
|
112
142
|
"""
|
|
113
143
|
获取MACD技术指标数据
|
|
@@ -14,11 +14,6 @@ class DataSourceError(Exception):
|
|
|
14
14
|
pass
|
|
15
15
|
|
|
16
16
|
|
|
17
|
-
class LoginError(DataSourceError):
|
|
18
|
-
"""Exception raised for login failures to the data source."""
|
|
19
|
-
pass
|
|
20
|
-
|
|
21
|
-
|
|
22
17
|
class NoDataFoundError(DataSourceError):
|
|
23
18
|
"""Exception raised when no data is found for the given query."""
|
|
24
19
|
pass
|
|
@@ -648,4 +643,20 @@ class FinancialDataInterface(ABC):
|
|
|
648
643
|
Raises:
|
|
649
644
|
DataSourceError: 当数据源出现错误时
|
|
650
645
|
"""
|
|
651
|
-
pass
|
|
646
|
+
pass
|
|
647
|
+
|
|
648
|
+
@abstractmethod
|
|
649
|
+
def get_intraday_changes(self, stock_code: str) -> Optional[List[Dict[Any, Any]]]:
|
|
650
|
+
"""
|
|
651
|
+
获取分时图盘口异动数据
|
|
652
|
+
|
|
653
|
+
Args:
|
|
654
|
+
stock_code: 股票代码,如 300750
|
|
655
|
+
|
|
656
|
+
Returns:
|
|
657
|
+
分时图盘口异动数据列表
|
|
658
|
+
|
|
659
|
+
Raises:
|
|
660
|
+
DataSourceError: 当数据源出现错误时
|
|
661
|
+
"""
|
|
662
|
+
pass
|
|
@@ -123,6 +123,74 @@ def format_technical_indicators_data(technical_data: List[Dict]) -> List[Dict]:
|
|
|
123
123
|
return formatted_data
|
|
124
124
|
|
|
125
125
|
|
|
126
|
+
def format_intraday_changes_data(intraday_changes: List[str]) -> List[Dict]:
|
|
127
|
+
"""
|
|
128
|
+
格式化分时图盘口异动数据
|
|
129
|
+
|
|
130
|
+
Args:
|
|
131
|
+
intraday_changes: 原始分时图盘口异动数据列表
|
|
132
|
+
|
|
133
|
+
Returns:
|
|
134
|
+
格式化后的分时图盘口异动数据列表
|
|
135
|
+
"""
|
|
136
|
+
formatted_data = []
|
|
137
|
+
|
|
138
|
+
# 事件类型码含义映射
|
|
139
|
+
event_type_map = {
|
|
140
|
+
1: "有大买盘",
|
|
141
|
+
101: "有大卖盘",
|
|
142
|
+
2: "大笔买入",
|
|
143
|
+
102: "大笔卖出",
|
|
144
|
+
201: "封涨停板",
|
|
145
|
+
301: "封跌停板",
|
|
146
|
+
202: "打开涨停",
|
|
147
|
+
302: "打开跌停",
|
|
148
|
+
203: "高开5日线",
|
|
149
|
+
303: "低开5日线",
|
|
150
|
+
204: "60日新高",
|
|
151
|
+
304: "60日新低",
|
|
152
|
+
401: "向上缺口",
|
|
153
|
+
501: "向下缺口",
|
|
154
|
+
402: "火箭发射",
|
|
155
|
+
502: "高台跳水",
|
|
156
|
+
403: "快速反弹",
|
|
157
|
+
503: "快速下跌",
|
|
158
|
+
404: "竞价上涨",
|
|
159
|
+
504: "竞价下跌",
|
|
160
|
+
405: "60日大幅上涨",
|
|
161
|
+
505: "60日大幅下跌"
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
for item in intraday_changes:
|
|
165
|
+
if not item:
|
|
166
|
+
continue
|
|
167
|
+
|
|
168
|
+
fields = item.split(',')
|
|
169
|
+
if len(fields) >= 7:
|
|
170
|
+
time_str = fields[0] # 时间
|
|
171
|
+
event_type_code = int(fields[4]) # 事件类型码
|
|
172
|
+
value = fields[5] # 具体数值
|
|
173
|
+
direction = fields[6] # 方向标识
|
|
174
|
+
|
|
175
|
+
# 获取事件类型描述
|
|
176
|
+
event_type_desc = event_type_map.get(event_type_code, f"未知事件({event_type_code})")
|
|
177
|
+
|
|
178
|
+
# 解析方向
|
|
179
|
+
direction_desc = "买入" if direction == "1" else "卖出" if direction == "2" else "未知"
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
formatted_item = {
|
|
183
|
+
'时间': time_str,
|
|
184
|
+
'事件类型': event_type_desc,
|
|
185
|
+
'具体数值': value,
|
|
186
|
+
'方向': direction_desc
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
formatted_data.append(formatted_item)
|
|
190
|
+
|
|
191
|
+
return formatted_data
|
|
192
|
+
|
|
193
|
+
|
|
126
194
|
def register_kline_tools(app: FastMCP, data_source: FinancialDataInterface):
|
|
127
195
|
"""
|
|
128
196
|
注册K线数据相关工具
|
|
@@ -254,4 +322,39 @@ def register_kline_tools(app: FastMCP, data_source: FinancialDataInterface):
|
|
|
254
322
|
|
|
255
323
|
except Exception as e:
|
|
256
324
|
logger.error(f"获取技术指标时出错: {e}")
|
|
257
|
-
return f"获取技术指标失败: {str(e)}"
|
|
325
|
+
return f"获取技术指标失败: {str(e)}"
|
|
326
|
+
|
|
327
|
+
@app.tool()
|
|
328
|
+
def get_intraday_changes(
|
|
329
|
+
stock_code: str,
|
|
330
|
+
) -> str:
|
|
331
|
+
"""
|
|
332
|
+
获取指定股票的分时图盘口异动数据,包括重要交易事件和异常波动信息。
|
|
333
|
+
|
|
334
|
+
Args:
|
|
335
|
+
stock_code: 股票代码,要在数字后加上交易所代码,格式如300750.SZ
|
|
336
|
+
|
|
337
|
+
Returns:
|
|
338
|
+
分时图盘口异动数据的Markdown表格
|
|
339
|
+
|
|
340
|
+
Examples:
|
|
341
|
+
- get_intraday_changes("300750.SZ")
|
|
342
|
+
"""
|
|
343
|
+
try:
|
|
344
|
+
# 从数据源获取原始数据
|
|
345
|
+
raw_intraday_changes = data_source.get_intraday_changes(stock_code)
|
|
346
|
+
|
|
347
|
+
if not raw_intraday_changes:
|
|
348
|
+
return f"未找到股票代码 '{stock_code}' 的分时图盘口异动数据"
|
|
349
|
+
|
|
350
|
+
# 格式化数据
|
|
351
|
+
formatted_data = format_intraday_changes_data(raw_intraday_changes)
|
|
352
|
+
|
|
353
|
+
# 生成Markdown表格
|
|
354
|
+
table = format_list_to_markdown_table(formatted_data)
|
|
355
|
+
|
|
356
|
+
return f"## {stock_code}分时图盘口异动数据\n\n{table}"
|
|
357
|
+
|
|
358
|
+
except Exception as e:
|
|
359
|
+
logger.error(f"获取分时图盘口异动时出错: {e}")
|
|
360
|
+
return f"获取分时图盘口异动失败: {str(e)}"
|
|
@@ -209,4 +209,7 @@ class WebCrawlerDataSource(FinancialDataInterface):
|
|
|
209
209
|
return self.smart_review_crawler.get_main_force_control(stock_code)
|
|
210
210
|
|
|
211
211
|
def get_participation_wish(self, stock_code: str) -> Optional[List[Dict[Any, Any]]]:
|
|
212
|
-
return self.smart_review_crawler.get_participation_wish(stock_code)
|
|
212
|
+
return self.smart_review_crawler.get_participation_wish(stock_code)
|
|
213
|
+
|
|
214
|
+
def get_intraday_changes(self, stock_code: str) -> Optional[List[Dict[Any, Any]]]:
|
|
215
|
+
return self.kline_spider.get_intraday_changes(stock_code)
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
from src.stock_mcp.crawler.real_time_data import RealTimeDataSpider
|
|
2
|
-
from src.stock_mcp.crawler.fundamental_data import FundamentalDataCrawler
|
|
3
|
-
|
|
4
|
-
print("获取股票代码300750.SZ的实时数据")
|
|
5
|
-
real_time_spider = RealTimeDataSpider()
|
|
6
|
-
real_time_data = real_time_spider.get_real_time_data("300750.SZ")
|
|
7
|
-
print(real_time_data)
|
|
8
|
-
|
|
9
|
-
print("获取股票代码300750.SZ的实时市场指数")
|
|
10
|
-
mark_indices = real_time_spider.get_real_time_market_indices()
|
|
11
|
-
print(mark_indices)
|
|
12
|
-
|
|
13
|
-
# print("获取股票代码300750.SZ的 main_business")
|
|
14
|
-
# fundamental_spider = FundamentalDataCrawler()
|
|
15
|
-
# main_business = fundamental_spider.get_main_business("300750.SZ")
|
|
16
|
-
# print(main_business)
|
|
File without changes
|
|
File without changes
|
{real_time_stock_mcp_service-1.1.2 → real_time_stock_mcp_service-1.2.1}/src/stock_mcp/__init__.py
RENAMED
|
File without changes
|
{real_time_stock_mcp_service-1.1.2 → real_time_stock_mcp_service-1.2.1}/src/stock_mcp/__main__.py
RENAMED
|
File without changes
|
{real_time_stock_mcp_service-1.1.2 → real_time_stock_mcp_service-1.2.1}/src/stock_mcp/app.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{real_time_stock_mcp_service-1.1.2 → real_time_stock_mcp_service-1.2.1}/src/stock_mcp/utils/utils.py
RENAMED
|
File without changes
|