akshare-one 0.2.0__tar.gz → 0.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.
- {akshare_one-0.2.0 → akshare_one-0.2.1}/PKG-INFO +9 -9
- {akshare_one-0.2.0 → akshare_one-0.2.1}/README.md +6 -6
- {akshare_one-0.2.0 → akshare_one-0.2.1}/akshare_one/insider.py +2 -5
- akshare_one-0.2.1/akshare_one/modules/financial/base.py +22 -0
- {akshare_one-0.2.0 → akshare_one-0.2.1}/akshare_one/modules/financial/sina.py +1 -4
- {akshare_one-0.2.0 → akshare_one-0.2.1}/akshare_one/modules/historical/base.py +0 -25
- {akshare_one-0.2.0 → akshare_one-0.2.1}/akshare_one/modules/historical/eastmoney.py +1 -2
- {akshare_one-0.2.0 → akshare_one-0.2.1}/akshare_one/modules/historical/sina.py +1 -2
- akshare_one-0.2.1/akshare_one/modules/insider/base.py +28 -0
- {akshare_one-0.2.0 → akshare_one-0.2.1}/akshare_one/modules/insider/xueqiu.py +1 -2
- akshare_one-0.2.1/akshare_one/modules/news/base.py +22 -0
- {akshare_one-0.2.0 → akshare_one-0.2.1}/akshare_one/modules/news/eastmoney.py +1 -2
- akshare_one-0.2.1/akshare_one/modules/realtime/base.py +27 -0
- {akshare_one-0.2.0 → akshare_one-0.2.1}/akshare_one/modules/realtime/eastmoney.py +1 -2
- {akshare_one-0.2.0 → akshare_one-0.2.1}/akshare_one/modules/realtime/xueqiu.py +1 -2
- {akshare_one-0.2.0 → akshare_one-0.2.1}/akshare_one/stock.py +1 -1
- {akshare_one-0.2.0 → akshare_one-0.2.1}/akshare_one.egg-info/PKG-INFO +9 -9
- {akshare_one-0.2.0 → akshare_one-0.2.1}/akshare_one.egg-info/SOURCES.txt +5 -1
- akshare_one-0.2.1/akshare_one.egg-info/requires.txt +2 -0
- {akshare_one-0.2.0 → akshare_one-0.2.1}/pyproject.toml +12 -5
- akshare_one-0.2.1/tests/test_financial.py +64 -0
- akshare_one-0.2.1/tests/test_insider.py +47 -0
- akshare_one-0.2.1/tests/test_news.py +50 -0
- akshare_one-0.2.1/tests/test_stock.py +101 -0
- akshare_one-0.2.0/akshare_one/modules/financial/base.py +0 -41
- akshare_one-0.2.0/akshare_one/modules/insider/base.py +0 -78
- akshare_one-0.2.0/akshare_one/modules/news/base.py +0 -51
- akshare_one-0.2.0/akshare_one/modules/realtime/base.py +0 -68
- akshare_one-0.2.0/akshare_one.egg-info/requires.txt +0 -2
- {akshare_one-0.2.0 → akshare_one-0.2.1}/LICENSE +0 -0
- {akshare_one-0.2.0 → akshare_one-0.2.1}/akshare_one/__init__.py +0 -0
- {akshare_one-0.2.0 → akshare_one-0.2.1}/akshare_one/financial.py +0 -0
- {akshare_one-0.2.0 → akshare_one-0.2.1}/akshare_one/modules/cache.py +0 -0
- {akshare_one-0.2.0 → akshare_one-0.2.1}/akshare_one/modules/financial/factory.py +0 -0
- {akshare_one-0.2.0 → akshare_one-0.2.1}/akshare_one/modules/historical/factory.py +0 -0
- {akshare_one-0.2.0 → akshare_one-0.2.1}/akshare_one/modules/insider/factory.py +0 -0
- {akshare_one-0.2.0 → akshare_one-0.2.1}/akshare_one/modules/news/factory.py +0 -0
- {akshare_one-0.2.0 → akshare_one-0.2.1}/akshare_one/modules/realtime/factory.py +0 -0
- {akshare_one-0.2.0 → akshare_one-0.2.1}/akshare_one/modules/utils.py +0 -0
- {akshare_one-0.2.0 → akshare_one-0.2.1}/akshare_one/news.py +0 -0
- {akshare_one-0.2.0 → akshare_one-0.2.1}/akshare_one.egg-info/dependency_links.txt +0 -0
- {akshare_one-0.2.0 → akshare_one-0.2.1}/akshare_one.egg-info/top_level.txt +0 -0
- {akshare_one-0.2.0 → akshare_one-0.2.1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: akshare-one
|
3
|
-
Version: 0.2.
|
3
|
+
Version: 0.2.1
|
4
4
|
Summary: Standardized interface for Chinese financial market data, built on AKShare with unified data formats and simplified APIs
|
5
5
|
License-Expression: MIT
|
6
6
|
Project-URL: Homepage, https://github.com/zwldarren/akshare-one
|
@@ -9,35 +9,35 @@ Keywords: akshare,financial-data,stock-data,quant
|
|
9
9
|
Requires-Python: >=3.12
|
10
10
|
Description-Content-Type: text/markdown
|
11
11
|
License-File: LICENSE
|
12
|
-
Requires-Dist: akshare>=1.16.
|
13
|
-
Requires-Dist: cachetools>=
|
12
|
+
Requires-Dist: akshare>=1.16.98
|
13
|
+
Requires-Dist: cachetools>=6.0.0
|
14
14
|
Dynamic: license-file
|
15
15
|
|
16
16
|
<div align="center">
|
17
17
|
<h1>AKShare One</h1>
|
18
18
|
<div>
|
19
|
-
<
|
19
|
+
<a href="README_zh.md">中文</a> | <strong>English</strong>
|
20
20
|
</div>
|
21
21
|
</div>
|
22
22
|
|
23
|
-
**AKShare One** is a
|
23
|
+
**AKShare One** is a data interface for obtaining Chinese A-shares, based on [AKShare](https://github.com/akfamily/akshare). It aims to simplify AKShare's usage and unify input/output formats from different data sources, making it easier to pass data to LLM.
|
24
24
|
|
25
25
|
## ✨ Features
|
26
26
|
|
27
27
|
- 📊 Unified stock code formats across data sources
|
28
28
|
- 🏗️ Standardized return data structures
|
29
|
-
- 🛠️ Simplified API
|
29
|
+
- 🛠️ Simplified API parameter design
|
30
30
|
- ⏱️ Automatic timestamp and adjustment handling
|
31
31
|
|
32
32
|
## 🚀 Core Features
|
33
33
|
|
34
|
-
|
|
35
|
-
|
34
|
+
| Function | Interface |
|
35
|
+
|------|------|
|
36
36
|
| Historical data | `get_hist_data` |
|
37
37
|
| Real-time quotes | `get_realtime_data` |
|
38
38
|
| Stock news | `get_news_data` |
|
39
39
|
| Financial data | `get_balance_sheet`/`get_income_statement`/`get_cash_flow` |
|
40
|
-
|
|
40
|
+
| Internal transactions | `get_inner_trade_data` |
|
41
41
|
|
42
42
|
## 📦 Quick Installation
|
43
43
|
|
@@ -1,28 +1,28 @@
|
|
1
1
|
<div align="center">
|
2
2
|
<h1>AKShare One</h1>
|
3
3
|
<div>
|
4
|
-
<
|
4
|
+
<a href="README_zh.md">中文</a> | <strong>English</strong>
|
5
5
|
</div>
|
6
6
|
</div>
|
7
7
|
|
8
|
-
**AKShare One** is a
|
8
|
+
**AKShare One** is a data interface for obtaining Chinese A-shares, based on [AKShare](https://github.com/akfamily/akshare). It aims to simplify AKShare's usage and unify input/output formats from different data sources, making it easier to pass data to LLM.
|
9
9
|
|
10
10
|
## ✨ Features
|
11
11
|
|
12
12
|
- 📊 Unified stock code formats across data sources
|
13
13
|
- 🏗️ Standardized return data structures
|
14
|
-
- 🛠️ Simplified API
|
14
|
+
- 🛠️ Simplified API parameter design
|
15
15
|
- ⏱️ Automatic timestamp and adjustment handling
|
16
16
|
|
17
17
|
## 🚀 Core Features
|
18
18
|
|
19
|
-
|
|
20
|
-
|
19
|
+
| Function | Interface |
|
20
|
+
|------|------|
|
21
21
|
| Historical data | `get_hist_data` |
|
22
22
|
| Real-time quotes | `get_realtime_data` |
|
23
23
|
| Stock news | `get_news_data` |
|
24
24
|
| Financial data | `get_balance_sheet`/`get_income_statement`/`get_cash_flow` |
|
25
|
-
|
|
25
|
+
| Internal transactions | `get_inner_trade_data` |
|
26
26
|
|
27
27
|
## 📦 Quick Installation
|
28
28
|
|
@@ -3,19 +3,16 @@
|
|
3
3
|
包含上市公司内部交易相关功能
|
4
4
|
"""
|
5
5
|
|
6
|
-
from typing import Optional
|
7
6
|
import pandas as pd
|
8
7
|
from .modules.insider.factory import InsiderDataFactory
|
9
8
|
|
10
9
|
|
11
|
-
def get_inner_trade_data(
|
12
|
-
symbol: Optional[str] = None, source: str = "xueqiu"
|
13
|
-
) -> "pd.DataFrame":
|
10
|
+
def get_inner_trade_data(symbol: str, source: str = "xueqiu") -> "pd.DataFrame":
|
14
11
|
"""获取雪球内部交易数据
|
15
12
|
|
16
13
|
Args:
|
17
14
|
source: 数据源 (目前支持 "xueqiu")
|
18
|
-
symbol:
|
15
|
+
symbol: 股票代码,如"600000"
|
19
16
|
|
20
17
|
Returns:
|
21
18
|
pd.DataFrame:
|
@@ -0,0 +1,22 @@
|
|
1
|
+
from abc import ABC, abstractmethod
|
2
|
+
import pandas as pd
|
3
|
+
|
4
|
+
|
5
|
+
class FinancialDataProvider(ABC):
|
6
|
+
def __init__(self, symbol: str) -> None:
|
7
|
+
self.symbol = symbol
|
8
|
+
|
9
|
+
@abstractmethod
|
10
|
+
def get_balance_sheet(self) -> pd.DataFrame:
|
11
|
+
"""Fetches balance sheet data"""
|
12
|
+
pass
|
13
|
+
|
14
|
+
@abstractmethod
|
15
|
+
def get_income_statement(self) -> pd.DataFrame:
|
16
|
+
"""Fetches income statement data"""
|
17
|
+
pass
|
18
|
+
|
19
|
+
@abstractmethod
|
20
|
+
def get_cash_flow(self) -> pd.DataFrame:
|
21
|
+
"""Fetches cash flow data"""
|
22
|
+
pass
|
@@ -3,7 +3,7 @@ import pandas as pd
|
|
3
3
|
import akshare as ak
|
4
4
|
|
5
5
|
from akshare_one.modules.cache import CACHE_CONFIG
|
6
|
-
from .base import FinancialDataProvider
|
6
|
+
from .base import FinancialDataProvider
|
7
7
|
|
8
8
|
|
9
9
|
class SinaFinancialReport(FinancialDataProvider):
|
@@ -13,7 +13,6 @@ class SinaFinancialReport(FinancialDataProvider):
|
|
13
13
|
f"sh{symbol}" if not symbol.startswith(("sh", "sz", "bj")) else symbol
|
14
14
|
)
|
15
15
|
|
16
|
-
@validate_financial_data
|
17
16
|
@cached(
|
18
17
|
CACHE_CONFIG["financial_cache"],
|
19
18
|
key=lambda self, symbol=None: f"sina_balance_{self.symbol}",
|
@@ -30,7 +29,6 @@ class SinaFinancialReport(FinancialDataProvider):
|
|
30
29
|
raw_df = ak.stock_financial_report_sina(stock=self.stock, symbol="资产负债表")
|
31
30
|
return self._clean_balance_data(raw_df)
|
32
31
|
|
33
|
-
@validate_financial_data
|
34
32
|
@cached(
|
35
33
|
CACHE_CONFIG["financial_cache"],
|
36
34
|
key=lambda self, symbol=None: f"sina_income_{self.symbol}",
|
@@ -47,7 +45,6 @@ class SinaFinancialReport(FinancialDataProvider):
|
|
47
45
|
raw_df = ak.stock_financial_report_sina(stock=self.stock, symbol="利润表")
|
48
46
|
return self._clean_income_data(raw_df)
|
49
47
|
|
50
|
-
@validate_financial_data
|
51
48
|
@cached(
|
52
49
|
CACHE_CONFIG["financial_cache"],
|
53
50
|
key=lambda self, symbol=None: f"sina_cash_{self.symbol}",
|
@@ -2,31 +2,6 @@ from abc import ABC, abstractmethod
|
|
2
2
|
import pandas as pd
|
3
3
|
|
4
4
|
|
5
|
-
def validate_hist_data(func):
|
6
|
-
"""Decorator to validate historical data returned by data providers"""
|
7
|
-
|
8
|
-
def wrapper(*args, **kwargs):
|
9
|
-
df = func(*args, **kwargs)
|
10
|
-
|
11
|
-
if not isinstance(df, pd.DataFrame):
|
12
|
-
raise ValueError("Returned data must be a pandas DataFrame")
|
13
|
-
|
14
|
-
required_columns = {"timestamp", "open", "high", "low", "close", "volume"}
|
15
|
-
missing_cols = required_columns - set(df.columns)
|
16
|
-
if missing_cols:
|
17
|
-
raise ValueError(f"Missing required columns: {missing_cols}")
|
18
|
-
|
19
|
-
if "timestamp" in df.columns:
|
20
|
-
if not pd.api.types.is_datetime64_any_dtype(df["timestamp"]):
|
21
|
-
raise ValueError("timestamp must be datetime64 dtype")
|
22
|
-
if df["timestamp"].dt.tz is None or str(df["timestamp"].dt.tz) != "UTC":
|
23
|
-
raise ValueError("timestamp must be in UTC timezone")
|
24
|
-
|
25
|
-
return df
|
26
|
-
|
27
|
-
return wrapper
|
28
|
-
|
29
|
-
|
30
5
|
class HistoricalDataProvider(ABC):
|
31
6
|
def __init__(
|
32
7
|
self,
|
@@ -1,5 +1,5 @@
|
|
1
1
|
from cachetools import cached
|
2
|
-
from .base import HistoricalDataProvider
|
2
|
+
from .base import HistoricalDataProvider
|
3
3
|
import akshare as ak
|
4
4
|
import pandas as pd
|
5
5
|
from ..cache import CACHE_CONFIG
|
@@ -8,7 +8,6 @@ from ..cache import CACHE_CONFIG
|
|
8
8
|
class EastMoneyHistorical(HistoricalDataProvider):
|
9
9
|
"""Adapter for EastMoney historical stock data API"""
|
10
10
|
|
11
|
-
@validate_hist_data
|
12
11
|
@cached(
|
13
12
|
cache=CACHE_CONFIG["hist_data_cache"],
|
14
13
|
key=lambda self: f"eastmoney_hist_{self.symbol}_{self.interval}_{self.interval_multiplier}_{self.adjust}",
|
@@ -1,5 +1,5 @@
|
|
1
1
|
from cachetools import cached
|
2
|
-
from .base import HistoricalDataProvider
|
2
|
+
from .base import HistoricalDataProvider
|
3
3
|
import akshare as ak
|
4
4
|
import pandas as pd
|
5
5
|
from ..cache import CACHE_CONFIG
|
@@ -8,7 +8,6 @@ from ..cache import CACHE_CONFIG
|
|
8
8
|
class SinaHistorical(HistoricalDataProvider):
|
9
9
|
"""Adapter for Sina historical stock data API"""
|
10
10
|
|
11
|
-
@validate_hist_data
|
12
11
|
@cached(
|
13
12
|
cache=CACHE_CONFIG["hist_data_cache"],
|
14
13
|
key=lambda self: f"sina_hist_{self.symbol}_{self.interval}_{self.interval_multiplier}_{self.adjust}",
|
@@ -0,0 +1,28 @@
|
|
1
|
+
from abc import ABC, abstractmethod
|
2
|
+
import pandas as pd
|
3
|
+
|
4
|
+
|
5
|
+
class InsiderDataProvider(ABC):
|
6
|
+
def __init__(self, symbol: str) -> None:
|
7
|
+
self.symbol = symbol
|
8
|
+
|
9
|
+
@abstractmethod
|
10
|
+
def get_inner_trade_data(self) -> pd.DataFrame:
|
11
|
+
"""Fetches insider trade data
|
12
|
+
|
13
|
+
Returns:
|
14
|
+
pd.DataFrame:
|
15
|
+
- symbol: 股票代码
|
16
|
+
- issuer: 股票名称
|
17
|
+
- name: 变动人
|
18
|
+
- title: 董监高职务
|
19
|
+
- transaction_date: 变动日期(UTC时区)
|
20
|
+
- transaction_shares: 变动股数
|
21
|
+
- transaction_price_per_share: 成交均价
|
22
|
+
- shares_owned_after_transaction: 变动后持股数
|
23
|
+
- relationship: 与董监高关系
|
24
|
+
- is_board_director: 是否为董事会成员
|
25
|
+
- transaction_value: 交易金额(变动股数*成交均价)
|
26
|
+
- shares_owned_before_transaction: 变动前持股数
|
27
|
+
"""
|
28
|
+
pass
|
@@ -1,7 +1,7 @@
|
|
1
1
|
from cachetools import cached
|
2
2
|
import pandas as pd
|
3
3
|
import akshare as ak
|
4
|
-
from .base import InsiderDataProvider
|
4
|
+
from .base import InsiderDataProvider
|
5
5
|
from ..utils import convert_xieqiu_symbol
|
6
6
|
from ..cache import CACHE_CONFIG
|
7
7
|
|
@@ -9,7 +9,6 @@ from ..cache import CACHE_CONFIG
|
|
9
9
|
class XueQiuInsider(InsiderDataProvider):
|
10
10
|
"""Provider for XueQiu insider trading data"""
|
11
11
|
|
12
|
-
@validate_insider_data
|
13
12
|
@cached(
|
14
13
|
cache=CACHE_CONFIG["financial_cache"],
|
15
14
|
key=lambda self, symbol=None: f"xueqiu_insider_{symbol if symbol else 'all'}",
|
@@ -0,0 +1,22 @@
|
|
1
|
+
from abc import ABC, abstractmethod
|
2
|
+
import pandas as pd
|
3
|
+
|
4
|
+
|
5
|
+
class NewsDataProvider(ABC):
|
6
|
+
def __init__(self, symbol: str) -> None:
|
7
|
+
self.symbol = symbol
|
8
|
+
|
9
|
+
@abstractmethod
|
10
|
+
def get_news_data(self) -> pd.DataFrame:
|
11
|
+
"""Fetches news data for given symbol
|
12
|
+
|
13
|
+
Returns:
|
14
|
+
pd.DataFrame:
|
15
|
+
- keyword: 关键词
|
16
|
+
- title: 新闻标题
|
17
|
+
- content: 新闻内容
|
18
|
+
- publish_time: 发布时间 (UTC)
|
19
|
+
- source: 文章来源
|
20
|
+
- url: 新闻链接
|
21
|
+
"""
|
22
|
+
pass
|
@@ -3,11 +3,10 @@ import pandas as pd
|
|
3
3
|
import akshare as ak
|
4
4
|
|
5
5
|
from ..cache import CACHE_CONFIG
|
6
|
-
from .base import NewsDataProvider
|
6
|
+
from .base import NewsDataProvider
|
7
7
|
|
8
8
|
|
9
9
|
class EastMoneyNews(NewsDataProvider):
|
10
|
-
@validate_news_data
|
11
10
|
@cached(
|
12
11
|
CACHE_CONFIG["news_cache"],
|
13
12
|
key=lambda self: f"eastmoney_news_{self.symbol}",
|
@@ -0,0 +1,27 @@
|
|
1
|
+
from abc import ABC, abstractmethod
|
2
|
+
import pandas as pd
|
3
|
+
|
4
|
+
|
5
|
+
class RealtimeDataProvider(ABC):
|
6
|
+
def __init__(self, symbol: str) -> None:
|
7
|
+
self.symbol = symbol
|
8
|
+
|
9
|
+
@abstractmethod
|
10
|
+
def get_current_data(self) -> pd.DataFrame:
|
11
|
+
"""Fetches realtime market data
|
12
|
+
|
13
|
+
Returns:
|
14
|
+
pd.DataFrame:
|
15
|
+
- symbol: 股票代码
|
16
|
+
- price: 最新价
|
17
|
+
- change: 涨跌额
|
18
|
+
- pct_change: 涨跌幅(%)
|
19
|
+
- timestamp: 时间戳
|
20
|
+
- volume: 成交量(手)
|
21
|
+
- amount: 成交额(元)
|
22
|
+
- open: 今开
|
23
|
+
- high: 最高
|
24
|
+
- low: 最低
|
25
|
+
- prev_close: 昨收
|
26
|
+
"""
|
27
|
+
pass
|
@@ -3,11 +3,10 @@ import pandas as pd
|
|
3
3
|
import akshare as ak
|
4
4
|
|
5
5
|
from ..cache import CACHE_CONFIG
|
6
|
-
from .base import RealtimeDataProvider
|
6
|
+
from .base import RealtimeDataProvider
|
7
7
|
|
8
8
|
|
9
9
|
class EastmoneyRealtime(RealtimeDataProvider):
|
10
|
-
@validate_realtime_data
|
11
10
|
@cached(
|
12
11
|
CACHE_CONFIG["realtime_cache"],
|
13
12
|
key=lambda self, symbol=None: f"eastmoney_{symbol if symbol else 'all'}",
|
@@ -3,11 +3,10 @@ import pandas as pd
|
|
3
3
|
import akshare as ak
|
4
4
|
from ..utils import convert_xieqiu_symbol
|
5
5
|
from ..cache import CACHE_CONFIG
|
6
|
-
from .base import RealtimeDataProvider
|
6
|
+
from .base import RealtimeDataProvider
|
7
7
|
|
8
8
|
|
9
9
|
class XueQiuRealtime(RealtimeDataProvider):
|
10
|
-
@validate_realtime_data
|
11
10
|
@cached(
|
12
11
|
cache=CACHE_CONFIG["realtime_cache"],
|
13
12
|
key=lambda self, symbol=None: f"xueqiu_{symbol}",
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: akshare-one
|
3
|
-
Version: 0.2.
|
3
|
+
Version: 0.2.1
|
4
4
|
Summary: Standardized interface for Chinese financial market data, built on AKShare with unified data formats and simplified APIs
|
5
5
|
License-Expression: MIT
|
6
6
|
Project-URL: Homepage, https://github.com/zwldarren/akshare-one
|
@@ -9,35 +9,35 @@ Keywords: akshare,financial-data,stock-data,quant
|
|
9
9
|
Requires-Python: >=3.12
|
10
10
|
Description-Content-Type: text/markdown
|
11
11
|
License-File: LICENSE
|
12
|
-
Requires-Dist: akshare>=1.16.
|
13
|
-
Requires-Dist: cachetools>=
|
12
|
+
Requires-Dist: akshare>=1.16.98
|
13
|
+
Requires-Dist: cachetools>=6.0.0
|
14
14
|
Dynamic: license-file
|
15
15
|
|
16
16
|
<div align="center">
|
17
17
|
<h1>AKShare One</h1>
|
18
18
|
<div>
|
19
|
-
<
|
19
|
+
<a href="README_zh.md">中文</a> | <strong>English</strong>
|
20
20
|
</div>
|
21
21
|
</div>
|
22
22
|
|
23
|
-
**AKShare One** is a
|
23
|
+
**AKShare One** is a data interface for obtaining Chinese A-shares, based on [AKShare](https://github.com/akfamily/akshare). It aims to simplify AKShare's usage and unify input/output formats from different data sources, making it easier to pass data to LLM.
|
24
24
|
|
25
25
|
## ✨ Features
|
26
26
|
|
27
27
|
- 📊 Unified stock code formats across data sources
|
28
28
|
- 🏗️ Standardized return data structures
|
29
|
-
- 🛠️ Simplified API
|
29
|
+
- 🛠️ Simplified API parameter design
|
30
30
|
- ⏱️ Automatic timestamp and adjustment handling
|
31
31
|
|
32
32
|
## 🚀 Core Features
|
33
33
|
|
34
|
-
|
|
35
|
-
|
34
|
+
| Function | Interface |
|
35
|
+
|------|------|
|
36
36
|
| Historical data | `get_hist_data` |
|
37
37
|
| Real-time quotes | `get_realtime_data` |
|
38
38
|
| Stock news | `get_news_data` |
|
39
39
|
| Financial data | `get_balance_sheet`/`get_income_statement`/`get_cash_flow` |
|
40
|
-
|
|
40
|
+
| Internal transactions | `get_inner_trade_data` |
|
41
41
|
|
42
42
|
## 📦 Quick Installation
|
43
43
|
|
@@ -29,4 +29,8 @@ akshare_one/modules/news/factory.py
|
|
29
29
|
akshare_one/modules/realtime/base.py
|
30
30
|
akshare_one/modules/realtime/eastmoney.py
|
31
31
|
akshare_one/modules/realtime/factory.py
|
32
|
-
akshare_one/modules/realtime/xueqiu.py
|
32
|
+
akshare_one/modules/realtime/xueqiu.py
|
33
|
+
tests/test_financial.py
|
34
|
+
tests/test_insider.py
|
35
|
+
tests/test_news.py
|
36
|
+
tests/test_stock.py
|
@@ -1,12 +1,12 @@
|
|
1
1
|
[project]
|
2
2
|
name = "akshare-one"
|
3
|
-
version = "0.2.
|
3
|
+
version = "0.2.1"
|
4
4
|
description = "Standardized interface for Chinese financial market data, built on AKShare with unified data formats and simplified APIs"
|
5
5
|
readme = "README.md"
|
6
6
|
requires-python = ">=3.12"
|
7
7
|
dependencies = [
|
8
|
-
"akshare>=1.16.
|
9
|
-
"cachetools>=
|
8
|
+
"akshare>=1.16.98",
|
9
|
+
"cachetools>=6.0.0",
|
10
10
|
]
|
11
11
|
license = "MIT"
|
12
12
|
keywords = ["akshare", "financial-data", "stock-data", "quant"]
|
@@ -18,6 +18,13 @@ Repository = "https://github.com/zwldarren/akshare-one.git"
|
|
18
18
|
[dependency-groups]
|
19
19
|
dev = [
|
20
20
|
"pre-commit>=4.2.0",
|
21
|
-
"pytest>=8.
|
22
|
-
"
|
21
|
+
"pytest>=8.4.0",
|
22
|
+
"pytest-cov>=6.1.1",
|
23
|
+
"ruff>=0.11.12",
|
23
24
|
]
|
25
|
+
|
26
|
+
[tool.pytest.ini_options]
|
27
|
+
testpaths = ["tests"]
|
28
|
+
python_files = "test_*.py"
|
29
|
+
python_functions = "test_*"
|
30
|
+
addopts = "-v --cov=akshare_one --cov-report=term-missing"
|
@@ -0,0 +1,64 @@
|
|
1
|
+
import pytest
|
2
|
+
from akshare_one import get_balance_sheet, get_income_statement, get_cash_flow
|
3
|
+
|
4
|
+
|
5
|
+
class TestBalanceSheet:
|
6
|
+
def test_basic_balance_sheet(self):
|
7
|
+
"""测试基本资产负债表获取功能"""
|
8
|
+
df = get_balance_sheet(symbol="600600")
|
9
|
+
assert not df.empty
|
10
|
+
required_columns = {
|
11
|
+
"report_date",
|
12
|
+
"currency",
|
13
|
+
"total_assets",
|
14
|
+
"current_assets",
|
15
|
+
"cash_and_equivalents",
|
16
|
+
"total_liabilities",
|
17
|
+
"current_liabilities",
|
18
|
+
"shareholders_equity",
|
19
|
+
}
|
20
|
+
assert required_columns.issubset(df.columns)
|
21
|
+
|
22
|
+
def test_invalid_symbol(self):
|
23
|
+
"""测试无效股票代码"""
|
24
|
+
with pytest.raises(Exception):
|
25
|
+
get_balance_sheet(symbol="INVALID")
|
26
|
+
|
27
|
+
|
28
|
+
class TestIncomeStatement:
|
29
|
+
def test_basic_income_statement(self):
|
30
|
+
"""测试基本利润表获取功能"""
|
31
|
+
df = get_income_statement(symbol="600600")
|
32
|
+
assert not df.empty
|
33
|
+
required_columns = {
|
34
|
+
"report_date",
|
35
|
+
"currency",
|
36
|
+
"revenue",
|
37
|
+
"cost_of_revenue",
|
38
|
+
"operating_profit",
|
39
|
+
"net_income",
|
40
|
+
"earnings_per_share",
|
41
|
+
}
|
42
|
+
assert required_columns.issubset(df.columns)
|
43
|
+
|
44
|
+
def test_multiple_periods(self):
|
45
|
+
"""测试多期数据获取"""
|
46
|
+
df = get_income_statement(symbol="600600")
|
47
|
+
assert len(df) >= 4 # 至少包含4个季度数据
|
48
|
+
|
49
|
+
|
50
|
+
class TestCashFlow:
|
51
|
+
def test_basic_cash_flow(self):
|
52
|
+
"""测试基本现金流量表获取功能"""
|
53
|
+
df = get_cash_flow(symbol="600600")
|
54
|
+
assert not df.empty
|
55
|
+
required_columns = {
|
56
|
+
"report_date",
|
57
|
+
"report_type",
|
58
|
+
"currency",
|
59
|
+
"net_cash_flow_from_operations",
|
60
|
+
"net_cash_flow_from_investing",
|
61
|
+
"net_cash_flow_from_financing",
|
62
|
+
"ending_cash_balance",
|
63
|
+
}
|
64
|
+
assert required_columns.issubset(df.columns)
|
@@ -0,0 +1,47 @@
|
|
1
|
+
import pytest
|
2
|
+
from akshare_one import get_inner_trade_data
|
3
|
+
from datetime import datetime, timedelta, timezone
|
4
|
+
|
5
|
+
|
6
|
+
class TestInnerTradeData:
|
7
|
+
def test_basic_inner_trade(self):
|
8
|
+
"""测试基本内部交易数据获取功能"""
|
9
|
+
df = get_inner_trade_data(symbol="600405")
|
10
|
+
assert not df.empty
|
11
|
+
required_columns = {
|
12
|
+
"symbol",
|
13
|
+
"issuer",
|
14
|
+
"name",
|
15
|
+
"title",
|
16
|
+
"transaction_date",
|
17
|
+
"transaction_shares",
|
18
|
+
"transaction_price_per_share",
|
19
|
+
"shares_owned_after_transaction",
|
20
|
+
"relationship",
|
21
|
+
"is_board_director",
|
22
|
+
"transaction_value",
|
23
|
+
}
|
24
|
+
assert required_columns.issubset(df.columns)
|
25
|
+
|
26
|
+
def test_transaction_date_range(self):
|
27
|
+
"""测试交易日期范围"""
|
28
|
+
df = get_inner_trade_data(symbol="600405")
|
29
|
+
now = datetime.now(timezone.utc)
|
30
|
+
one_year_ago = now - timedelta(days=365)
|
31
|
+
|
32
|
+
# 验证交易日期在合理范围内
|
33
|
+
assert all(one_year_ago <= ts <= now for ts in df["transaction_date"])
|
34
|
+
|
35
|
+
def test_transaction_value_calculation(self):
|
36
|
+
"""测试交易金额计算正确性"""
|
37
|
+
df = get_inner_trade_data(symbol="600405")
|
38
|
+
sample = df.iloc[0]
|
39
|
+
calculated_value = (
|
40
|
+
sample["transaction_shares"] * sample["transaction_price_per_share"]
|
41
|
+
)
|
42
|
+
assert abs(sample["transaction_value"] - calculated_value) < 0.01
|
43
|
+
|
44
|
+
def test_invalid_source(self):
|
45
|
+
"""测试无效数据源"""
|
46
|
+
with pytest.raises(Exception):
|
47
|
+
get_inner_trade_data("600405", source="invalid")
|
@@ -0,0 +1,50 @@
|
|
1
|
+
import pytest
|
2
|
+
from akshare_one import get_news_data
|
3
|
+
from datetime import datetime, timedelta, timezone
|
4
|
+
|
5
|
+
|
6
|
+
class TestNewsData:
|
7
|
+
def test_basic_news_data(self):
|
8
|
+
"""测试基本新闻数据获取功能"""
|
9
|
+
df = get_news_data(symbol="300059")
|
10
|
+
assert not df.empty
|
11
|
+
required_columns = {
|
12
|
+
"keyword",
|
13
|
+
"title",
|
14
|
+
"content",
|
15
|
+
"publish_time",
|
16
|
+
"source",
|
17
|
+
"url",
|
18
|
+
}
|
19
|
+
assert required_columns.issubset(df.columns)
|
20
|
+
|
21
|
+
# 验证发布时间格式
|
22
|
+
assert isinstance(df.iloc[0]["publish_time"], datetime)
|
23
|
+
|
24
|
+
def test_news_data_time_range(self):
|
25
|
+
"""测试新闻数据时间范围"""
|
26
|
+
df = get_news_data(symbol="300059")
|
27
|
+
now = datetime.now(timezone.utc)
|
28
|
+
one_year_ago = now - timedelta(days=365)
|
29
|
+
|
30
|
+
# 验证新闻发布时间在合理范围内
|
31
|
+
assert all(one_year_ago <= ts <= now for ts in df["publish_time"])
|
32
|
+
|
33
|
+
def test_news_content_quality(self):
|
34
|
+
"""测试新闻内容质量"""
|
35
|
+
df = get_news_data(symbol="300059")
|
36
|
+
sample_news = df.iloc[0]
|
37
|
+
|
38
|
+
assert len(sample_news["title"]) > 0
|
39
|
+
assert len(sample_news["content"]) > 0
|
40
|
+
assert sample_news["url"].startswith("http")
|
41
|
+
|
42
|
+
def test_invalid_symbol(self):
|
43
|
+
"""测试无效股票代码"""
|
44
|
+
with pytest.raises(Exception):
|
45
|
+
get_news_data(symbol="INVALID")
|
46
|
+
|
47
|
+
def test_multiple_pages(self):
|
48
|
+
"""测试多页新闻数据"""
|
49
|
+
df = get_news_data(symbol="300059")
|
50
|
+
assert len(df) >= 10 # 至少获取10条新闻
|
@@ -0,0 +1,101 @@
|
|
1
|
+
import pytest
|
2
|
+
from akshare_one import get_hist_data, get_realtime_data
|
3
|
+
|
4
|
+
|
5
|
+
class TestHistData:
|
6
|
+
def test_basic_hist_data(self):
|
7
|
+
"""测试基本历史数据获取功能"""
|
8
|
+
df = get_hist_data(
|
9
|
+
symbol="600000",
|
10
|
+
interval="day",
|
11
|
+
start_date="2024-01-01",
|
12
|
+
end_date="2024-01-31",
|
13
|
+
)
|
14
|
+
assert not df.empty
|
15
|
+
assert set(df.columns) == {
|
16
|
+
"timestamp",
|
17
|
+
"open",
|
18
|
+
"high",
|
19
|
+
"low",
|
20
|
+
"close",
|
21
|
+
"volume",
|
22
|
+
}
|
23
|
+
assert len(df) > 0
|
24
|
+
|
25
|
+
def test_hist_data_with_adjust(self):
|
26
|
+
"""测试复权历史数据"""
|
27
|
+
df_qfq = get_hist_data(
|
28
|
+
symbol="600000",
|
29
|
+
interval="day",
|
30
|
+
adjust="qfq",
|
31
|
+
start_date="2024-01-01",
|
32
|
+
end_date="2024-01-31",
|
33
|
+
)
|
34
|
+
df_hfq = get_hist_data(
|
35
|
+
symbol="600000",
|
36
|
+
interval="day",
|
37
|
+
adjust="hfq",
|
38
|
+
start_date="2024-01-01",
|
39
|
+
end_date="2024-01-31",
|
40
|
+
)
|
41
|
+
assert not df_qfq.equals(df_hfq)
|
42
|
+
|
43
|
+
def test_minute_hist_data(self):
|
44
|
+
"""测试新浪数据源的分钟级历史数据"""
|
45
|
+
df = get_hist_data(
|
46
|
+
symbol="600900",
|
47
|
+
interval="minute",
|
48
|
+
interval_multiplier=5,
|
49
|
+
start_date="2025-05-01",
|
50
|
+
end_date="2024-05-30",
|
51
|
+
source="sina",
|
52
|
+
)
|
53
|
+
assert not df.empty
|
54
|
+
assert len(df) > 0
|
55
|
+
|
56
|
+
def test_invalid_symbol(self):
|
57
|
+
"""测试无效股票代码"""
|
58
|
+
with pytest.raises(Exception):
|
59
|
+
get_hist_data(
|
60
|
+
symbol="INVALID",
|
61
|
+
interval="day",
|
62
|
+
start_date="2024-01-01",
|
63
|
+
end_date="2024-01-31",
|
64
|
+
)
|
65
|
+
|
66
|
+
|
67
|
+
class TestRealtimeData:
|
68
|
+
def test_basic_realtime_data(self):
|
69
|
+
"""测试基本实时数据获取"""
|
70
|
+
df = get_realtime_data(symbol="600000")
|
71
|
+
assert not df.empty
|
72
|
+
assert set(df.columns) == {
|
73
|
+
"symbol",
|
74
|
+
"price",
|
75
|
+
"change",
|
76
|
+
"pct_change",
|
77
|
+
"timestamp",
|
78
|
+
"volume",
|
79
|
+
"amount",
|
80
|
+
"open",
|
81
|
+
"high",
|
82
|
+
"low",
|
83
|
+
"prev_close",
|
84
|
+
}
|
85
|
+
|
86
|
+
def test_all_realtime_data(self):
|
87
|
+
"""测试获取所有股票实时数据"""
|
88
|
+
df = get_realtime_data()
|
89
|
+
assert not df.empty
|
90
|
+
assert "600000" in df["symbol"].values
|
91
|
+
|
92
|
+
def test_xueqiu_source(self):
|
93
|
+
"""测试雪球数据源"""
|
94
|
+
df = get_realtime_data(symbol="600000", source="xueqiu")
|
95
|
+
assert not df.empty
|
96
|
+
assert df.iloc[0]["symbol"] == "600000"
|
97
|
+
|
98
|
+
def test_invalid_source(self):
|
99
|
+
"""测试无效数据源"""
|
100
|
+
with pytest.raises(Exception):
|
101
|
+
get_realtime_data(symbol="600000", source="invalid")
|
@@ -1,41 +0,0 @@
|
|
1
|
-
from abc import ABC, abstractmethod
|
2
|
-
import pandas as pd
|
3
|
-
|
4
|
-
|
5
|
-
def validate_financial_data(func):
|
6
|
-
"""Decorator to validate financial data returned by data providers"""
|
7
|
-
|
8
|
-
def wrapper(*args, **kwargs):
|
9
|
-
df = func(*args, **kwargs)
|
10
|
-
|
11
|
-
if not isinstance(df, pd.DataFrame):
|
12
|
-
raise ValueError("Returned data must be a pandas DataFrame")
|
13
|
-
|
14
|
-
# Validate report_date if present
|
15
|
-
if "report_date" in df.columns:
|
16
|
-
if not pd.api.types.is_datetime64_any_dtype(df["report_date"]):
|
17
|
-
raise ValueError("report_date must be datetime64 dtype")
|
18
|
-
|
19
|
-
return df
|
20
|
-
|
21
|
-
return wrapper
|
22
|
-
|
23
|
-
|
24
|
-
class FinancialDataProvider(ABC):
|
25
|
-
def __init__(self, symbol: str) -> None:
|
26
|
-
self.symbol = symbol
|
27
|
-
|
28
|
-
@abstractmethod
|
29
|
-
def get_balance_sheet(self) -> pd.DataFrame:
|
30
|
-
"""Fetches balance sheet data"""
|
31
|
-
pass
|
32
|
-
|
33
|
-
@abstractmethod
|
34
|
-
def get_income_statement(self) -> pd.DataFrame:
|
35
|
-
"""Fetches income statement data"""
|
36
|
-
pass
|
37
|
-
|
38
|
-
@abstractmethod
|
39
|
-
def get_cash_flow(self) -> pd.DataFrame:
|
40
|
-
"""Fetches cash flow data"""
|
41
|
-
pass
|
@@ -1,78 +0,0 @@
|
|
1
|
-
from abc import ABC, abstractmethod
|
2
|
-
import pandas as pd
|
3
|
-
from typing import Optional
|
4
|
-
|
5
|
-
|
6
|
-
def validate_insider_data(func):
|
7
|
-
"""Decorator to validate insider trading data returned by data providers"""
|
8
|
-
|
9
|
-
def wrapper(*args, **kwargs):
|
10
|
-
df = func(*args, **kwargs)
|
11
|
-
|
12
|
-
if not isinstance(df, pd.DataFrame):
|
13
|
-
raise ValueError("Returned data must be a pandas DataFrame")
|
14
|
-
|
15
|
-
# Required fields for insider trading data
|
16
|
-
required_fields = {
|
17
|
-
"symbol",
|
18
|
-
"issuer",
|
19
|
-
"name",
|
20
|
-
"transaction_date",
|
21
|
-
"transaction_shares",
|
22
|
-
"transaction_price_per_share",
|
23
|
-
}
|
24
|
-
if not required_fields.issubset(df.columns):
|
25
|
-
missing = required_fields - set(df.columns)
|
26
|
-
raise ValueError(f"Missing required fields: {missing}")
|
27
|
-
|
28
|
-
# Validate timestamp if present
|
29
|
-
if "transaction_date" in df.columns:
|
30
|
-
if not pd.api.types.is_datetime64_any_dtype(df["transaction_date"]):
|
31
|
-
raise ValueError("transaction_date must be datetime64 dtype")
|
32
|
-
if (
|
33
|
-
df["transaction_date"].dt.tz is None
|
34
|
-
or str(df["transaction_date"].dt.tz) != "UTC"
|
35
|
-
):
|
36
|
-
raise ValueError("transaction_date must be in UTC timezone")
|
37
|
-
|
38
|
-
# Validate numeric fields
|
39
|
-
numeric_fields = {
|
40
|
-
"transaction_shares",
|
41
|
-
"transaction_price_per_share",
|
42
|
-
"transaction_value",
|
43
|
-
"shares_owned_before_transaction",
|
44
|
-
"shares_owned_after_transaction",
|
45
|
-
}
|
46
|
-
for field in numeric_fields & set(df.columns):
|
47
|
-
if not pd.api.types.is_numeric_dtype(df[field]):
|
48
|
-
raise ValueError(f"{field} must be numeric")
|
49
|
-
|
50
|
-
return df
|
51
|
-
|
52
|
-
return wrapper
|
53
|
-
|
54
|
-
|
55
|
-
class InsiderDataProvider(ABC):
|
56
|
-
def __init__(self, symbol: Optional[str] = None) -> None:
|
57
|
-
self.symbol = symbol
|
58
|
-
|
59
|
-
@abstractmethod
|
60
|
-
def get_inner_trade_data(self, symbol: Optional[str] = None) -> pd.DataFrame:
|
61
|
-
"""Fetches insider trade data
|
62
|
-
|
63
|
-
Returns:
|
64
|
-
pd.DataFrame:
|
65
|
-
- symbol: 股票代码
|
66
|
-
- issuer: 股票名称
|
67
|
-
- name: 变动人
|
68
|
-
- title: 董监高职务
|
69
|
-
- transaction_date: 变动日期(UTC时区)
|
70
|
-
- transaction_shares: 变动股数
|
71
|
-
- transaction_price_per_share: 成交均价
|
72
|
-
- shares_owned_after_transaction: 变动后持股数
|
73
|
-
- relationship: 与董监高关系
|
74
|
-
- is_board_director: 是否为董事会成员
|
75
|
-
- transaction_value: 交易金额(变动股数*成交均价)
|
76
|
-
- shares_owned_before_transaction: 变动前持股数
|
77
|
-
"""
|
78
|
-
pass
|
@@ -1,51 +0,0 @@
|
|
1
|
-
from abc import ABC, abstractmethod
|
2
|
-
import pandas as pd
|
3
|
-
|
4
|
-
|
5
|
-
def validate_news_data(func):
|
6
|
-
"""Decorator to validate news data returned by data providers"""
|
7
|
-
|
8
|
-
def wrapper(*args, **kwargs):
|
9
|
-
df = func(*args, **kwargs)
|
10
|
-
|
11
|
-
if not isinstance(df, pd.DataFrame):
|
12
|
-
raise ValueError("Returned data must be a pandas DataFrame")
|
13
|
-
|
14
|
-
# Required fields
|
15
|
-
required_fields = {"title", "publish_time"}
|
16
|
-
if not required_fields & set(df.columns):
|
17
|
-
raise ValueError(f"Must contain all required fields: {required_fields}")
|
18
|
-
|
19
|
-
# Validate publish_time if present
|
20
|
-
if "publish_time" in df.columns:
|
21
|
-
if not pd.api.types.is_datetime64_any_dtype(df["publish_time"]):
|
22
|
-
raise ValueError("publish_time must be datetime64 dtype")
|
23
|
-
if (
|
24
|
-
df["publish_time"].dt.tz is None
|
25
|
-
or str(df["publish_time"].dt.tz) != "UTC"
|
26
|
-
):
|
27
|
-
raise ValueError("publish_time must be in UTC timezone")
|
28
|
-
|
29
|
-
return df
|
30
|
-
|
31
|
-
return wrapper
|
32
|
-
|
33
|
-
|
34
|
-
class NewsDataProvider(ABC):
|
35
|
-
def __init__(self, symbol: str) -> None:
|
36
|
-
self.symbol = symbol
|
37
|
-
|
38
|
-
@abstractmethod
|
39
|
-
def get_news_data(self) -> pd.DataFrame:
|
40
|
-
"""Fetches news data for given symbol
|
41
|
-
|
42
|
-
Returns:
|
43
|
-
pd.DataFrame:
|
44
|
-
- keyword: 关键词
|
45
|
-
- title: 新闻标题
|
46
|
-
- content: 新闻内容
|
47
|
-
- publish_time: 发布时间 (UTC)
|
48
|
-
- source: 文章来源
|
49
|
-
- url: 新闻链接
|
50
|
-
"""
|
51
|
-
pass
|
@@ -1,68 +0,0 @@
|
|
1
|
-
from abc import ABC, abstractmethod
|
2
|
-
import pandas as pd
|
3
|
-
|
4
|
-
|
5
|
-
def validate_realtime_data(func):
|
6
|
-
"""Decorator to validate realtime data returned by data providers"""
|
7
|
-
|
8
|
-
def wrapper(*args, **kwargs):
|
9
|
-
df = func(*args, **kwargs)
|
10
|
-
|
11
|
-
if not isinstance(df, pd.DataFrame):
|
12
|
-
raise ValueError("Returned data must be a pandas DataFrame")
|
13
|
-
|
14
|
-
# At least one of these core fields must be present
|
15
|
-
core_fields = {"timestamp", "price", "volume"}
|
16
|
-
if not core_fields & set(df.columns):
|
17
|
-
raise ValueError(f"Must contain at least one of: {core_fields}")
|
18
|
-
|
19
|
-
# Validate timestamp if present
|
20
|
-
if "timestamp" in df.columns:
|
21
|
-
if not pd.api.types.is_datetime64_any_dtype(df["timestamp"]):
|
22
|
-
raise ValueError("timestamp must be datetime64 dtype")
|
23
|
-
if df["timestamp"].dt.tz is None or str(df["timestamp"].dt.tz) != "UTC":
|
24
|
-
raise ValueError("timestamp must be in UTC timezone")
|
25
|
-
|
26
|
-
# Validate numeric fields if present
|
27
|
-
numeric_fields = {
|
28
|
-
"price",
|
29
|
-
"change",
|
30
|
-
"pct_change",
|
31
|
-
"open",
|
32
|
-
"high",
|
33
|
-
"low",
|
34
|
-
"prev_close",
|
35
|
-
"amount",
|
36
|
-
}
|
37
|
-
for field in numeric_fields & set(df.columns):
|
38
|
-
if not pd.api.types.is_numeric_dtype(df[field]):
|
39
|
-
raise ValueError(f"{field} must be numeric")
|
40
|
-
|
41
|
-
return df
|
42
|
-
|
43
|
-
return wrapper
|
44
|
-
|
45
|
-
|
46
|
-
class RealtimeDataProvider(ABC):
|
47
|
-
def __init__(self, symbol: str) -> None:
|
48
|
-
self.symbol = symbol
|
49
|
-
|
50
|
-
@abstractmethod
|
51
|
-
def get_current_data(self) -> pd.DataFrame:
|
52
|
-
"""Fetches realtime market data
|
53
|
-
|
54
|
-
Returns:
|
55
|
-
pd.DataFrame:
|
56
|
-
- symbol: 股票代码
|
57
|
-
- price: 最新价
|
58
|
-
- change: 涨跌额
|
59
|
-
- pct_change: 涨跌幅(%)
|
60
|
-
- timestamp: 时间戳
|
61
|
-
- volume: 成交量(手)
|
62
|
-
- amount: 成交额(元)
|
63
|
-
- open: 今开
|
64
|
-
- high: 最高
|
65
|
-
- low: 最低
|
66
|
-
- prev_close: 昨收
|
67
|
-
"""
|
68
|
-
pass
|
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
|