akshare-one 0.3.5.1__py3-none-any.whl → 0.3.6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,80 @@
1
+ import requests
2
+ from typing import Dict, Any
3
+
4
+
5
+ class EastMoneyClient:
6
+ """
7
+ A client for interacting directly with EastMoney's data APIs.
8
+ This class handles session management, request signing, and API calls.
9
+ """
10
+
11
+ def __init__(self):
12
+ self.session = requests.Session()
13
+
14
+ def _get_security_id(self, symbol: str) -> str:
15
+ """
16
+ Converts a stock symbol to EastMoney's internal secid format.
17
+ e.g., '600519' -> '1.600519', '000001' -> '0.000001'
18
+ """
19
+ symbol = symbol.upper()
20
+ if symbol.startswith("SZ"):
21
+ market = "0"
22
+ code = symbol[2:]
23
+ elif symbol.startswith("SH"):
24
+ market = "1"
25
+ code = symbol[2:]
26
+ elif symbol.startswith("HK"):
27
+ market = "116"
28
+ code = symbol[2:]
29
+ elif len(symbol) == 6:
30
+ if symbol.startswith(("000", "001", "002", "003", "300", "200")):
31
+ market = "0"
32
+ elif symbol.startswith(("600", "601", "603", "605", "688", "900")):
33
+ market = "1"
34
+ else:
35
+ market = "0" # Default to SZ for ambiguity
36
+ code = symbol
37
+ elif len(symbol) == 5: # HK Market
38
+ market = "116"
39
+ code = symbol
40
+ else:
41
+ market = "0"
42
+ code = symbol
43
+ return f"{market}.{code}"
44
+
45
+ def fetch_historical_klines(
46
+ self, symbol: str, klt: str, fqt: str, start_date: str, end_date: str
47
+ ) -> Dict[str, Any]:
48
+ """
49
+ Fetches historical K-line (candlestick) data.
50
+ """
51
+ url = "https://push2his.eastmoney.com/api/qt/stock/kline/get"
52
+ secid = self._get_security_id(symbol)
53
+ params = {
54
+ "fields1": "f1,f2,f3,f4,f5,f6",
55
+ "fields2": "f51,f52,f53,f54,f55,f56,f57,f58,f59,f60,f61",
56
+ "klt": klt,
57
+ "fqt": fqt,
58
+ "secid": secid,
59
+ "beg": start_date,
60
+ "end": end_date,
61
+ }
62
+ response = self.session.get(url, params=params)
63
+ response.raise_for_status()
64
+ return response.json()
65
+
66
+ def fetch_realtime_quote(self, symbol: str) -> Dict[str, Any]:
67
+ """
68
+ Fetches real-time quote data for a single stock.
69
+ """
70
+ url = "https://push2.eastmoney.com/api/qt/stock/get"
71
+ secid = self._get_security_id(symbol)
72
+ params = {
73
+ "invt": "2",
74
+ "fltt": "2",
75
+ "fields": "f43,f57,f58,f169,f170,f46,f60,f44,f51,f168,f47,f164,f163,f116,f60,f45,f52,f50,f48,f167,f117,f71,f161,f49,f530",
76
+ "secid": secid,
77
+ }
78
+ response = self.session.get(url, params=params)
79
+ response.raise_for_status()
80
+ return response.json()
@@ -0,0 +1,102 @@
1
+ import pandas as pd
2
+ from typing import Dict, Any
3
+
4
+
5
+ def parse_kline_data(data: Dict[str, Any]) -> pd.DataFrame:
6
+ """
7
+ Parses K-line data from the API response into a pandas DataFrame.
8
+ """
9
+ klines = data.get("data", {}).get("klines", [])
10
+ if not klines:
11
+ return pd.DataFrame(
12
+ columns=["timestamp", "open", "high", "low", "close", "volume"]
13
+ )
14
+
15
+ records = []
16
+ for kline in klines:
17
+ parts = kline.split(",")
18
+ if len(parts) >= 6:
19
+ records.append(
20
+ {
21
+ "timestamp": parts[0],
22
+ "open": float(parts[1]),
23
+ "close": float(parts[2]),
24
+ "high": float(parts[3]),
25
+ "low": float(parts[4]),
26
+ "volume": int(parts[5]),
27
+ }
28
+ )
29
+
30
+ df = pd.DataFrame(records)
31
+ if not df.empty:
32
+ df["timestamp"] = pd.to_datetime(df["timestamp"])
33
+ df["timestamp"] = df["timestamp"].dt.tz_localize("Asia/Shanghai")
34
+ df = df[["timestamp", "open", "high", "low", "close", "volume"]]
35
+ return df
36
+
37
+
38
+ def parse_realtime_data(data: Dict[str, Any]) -> pd.DataFrame:
39
+ """
40
+ Parses real-time quote data from the API response into a pandas DataFrame.
41
+ """
42
+ stock_data = data.get("data")
43
+ if not stock_data:
44
+ return pd.DataFrame()
45
+
46
+ df = pd.DataFrame(
47
+ [
48
+ {
49
+ "symbol": stock_data.get("f57"),
50
+ "price": stock_data.get("f43"),
51
+ "change": stock_data.get("f169"),
52
+ "pct_change": stock_data.get("f170"),
53
+ "volume": stock_data.get("f47"),
54
+ "amount": stock_data.get("f48"),
55
+ "open": stock_data.get("f46"),
56
+ "high": stock_data.get("f44"),
57
+ "low": stock_data.get("f45"),
58
+ "prev_close": stock_data.get("f60"),
59
+ }
60
+ ]
61
+ )
62
+ df["timestamp"] = pd.Timestamp.now(tz="Asia/Shanghai")
63
+ return df
64
+
65
+
66
+ def resample_historical_data(
67
+ df: pd.DataFrame, interval: str, multiplier: int
68
+ ) -> pd.DataFrame:
69
+ """
70
+ Resamples historical data to a specified frequency.
71
+ """
72
+ if df.empty or multiplier <= 1:
73
+ return df
74
+
75
+ df = df.set_index("timestamp")
76
+
77
+ freq_map = {
78
+ "day": f"{multiplier}D",
79
+ "week": f"{multiplier}W-MON",
80
+ "month": f"{multiplier}MS",
81
+ "year": f"{multiplier * 12}MS",
82
+ }
83
+ freq = freq_map.get(interval)
84
+
85
+ if not freq:
86
+ return df.reset_index()
87
+
88
+ resampled = (
89
+ df.resample(freq)
90
+ .agg(
91
+ {
92
+ "open": "first",
93
+ "high": "max",
94
+ "low": "min",
95
+ "close": "last",
96
+ "volume": "sum",
97
+ }
98
+ )
99
+ .dropna()
100
+ )
101
+
102
+ return resampled.reset_index()
@@ -0,0 +1,183 @@
1
+ import pandas as pd
2
+ import requests
3
+
4
+ from akshare_one.modules.cache import cache
5
+ from .base import FinancialDataProvider
6
+
7
+
8
+ class EastMoneyDirectFinancialReport(FinancialDataProvider):
9
+ _balance_sheet_rename_map = {
10
+ "REPORT_DATE": "report_date",
11
+ "TOTAL_ASSETS": "total_assets",
12
+ "FIXED_ASSET": "fixed_assets_net",
13
+ "MONETARYFUNDS": "cash_and_equivalents",
14
+ "ACCOUNTS_RECE": "accounts_receivable",
15
+ "INVENTORY": "inventory",
16
+ "TOTAL_LIABILITIES": "total_liabilities",
17
+ "ACCOUNTS_PAYABLE": "trade_and_non_trade_payables",
18
+ "ADVANCE_RECEIVABLES": "deferred_revenue",
19
+ "TOTAL_EQUITY": "shareholders_equity",
20
+ }
21
+
22
+ _income_statement_rename_map = {
23
+ "REPORT_DATE": "report_date",
24
+ "TOTAL_OPERATE_INCOME": "revenue",
25
+ "TOTAL_OPERATE_COST": "total_operating_costs",
26
+ "OPERATE_PROFIT": "operating_profit",
27
+ "PARENT_NETPROFIT": "net_income_common_stock",
28
+ }
29
+
30
+ _cash_flow_rename_map = {
31
+ "REPORT_DATE": "report_date",
32
+ "NETCASH_OPERATE": "net_cash_flow_from_operations",
33
+ "NETCASH_INVEST": "net_cash_flow_from_investing",
34
+ "NETCASH_FINANCE": "net_cash_flow_from_financing",
35
+ "CCE_ADD": "change_in_cash_and_equivalents",
36
+ }
37
+
38
+ def __init__(self, symbol):
39
+ super().__init__(symbol)
40
+
41
+ def get_income_statement(self):
42
+ pass
43
+
44
+ def get_balance_sheet(self):
45
+ pass
46
+
47
+ def get_cash_flow(self):
48
+ pass
49
+
50
+ @cache(
51
+ "financial_cache",
52
+ key=lambda self, symbol=None: f"eastmoney_financial_metrics_{self.symbol}",
53
+ )
54
+ def get_financial_metrics(self) -> pd.DataFrame:
55
+ """获取三大财务报表关键指标"""
56
+ balance_sheet = self._fetch_balance_sheet()
57
+ income_statement = self._fetch_income_statement()
58
+ cash_flow = self._fetch_cash_flow()
59
+
60
+ if balance_sheet.empty and income_statement.empty and cash_flow.empty:
61
+ return pd.DataFrame()
62
+
63
+ merged = pd.merge(
64
+ balance_sheet, income_statement, on="report_date", how="outer"
65
+ )
66
+ merged = pd.merge(merged, cash_flow, on="report_date", how="outer")
67
+
68
+ # Convert report_date to datetime and format as YYYY-MM-DD
69
+ merged["report_date"] = pd.to_datetime(merged["report_date"]).dt.strftime(
70
+ "%Y-%m-%d"
71
+ )
72
+
73
+ # Sort by report_date in descending order (most recent first)
74
+ merged = merged.sort_values("report_date", ascending=False).reset_index(
75
+ drop=True
76
+ )
77
+
78
+ return merged
79
+
80
+ def _fetch_balance_sheet(self) -> pd.DataFrame:
81
+ """
82
+ Get stock balance sheet data from East Money API
83
+ """
84
+ try:
85
+ # API endpoint and parameters
86
+ api_url = "https://datacenter-web.eastmoney.com/api/data/v1/get"
87
+ params = {
88
+ "reportName": "RPT_DMSK_FN_BALANCE",
89
+ "filter": f'(SECURITY_CODE="{self.symbol}")',
90
+ "pageNumber": "1",
91
+ "pageSize": "1000",
92
+ "sortColumns": "REPORT_DATE",
93
+ "sortTypes": "-1",
94
+ "columns": ",".join(self._balance_sheet_rename_map.keys()),
95
+ }
96
+
97
+ # Fetch data from API
98
+ response = requests.get(api_url, params=params)
99
+ response.raise_for_status()
100
+ data = response.json()
101
+
102
+ # Extract the actual data
103
+ if data.get("result") and data["result"].get("data"):
104
+ df = pd.DataFrame(data["result"]["data"])
105
+ df.rename(columns=self._balance_sheet_rename_map, inplace=True)
106
+ return df
107
+ else:
108
+ print("No balance sheet data found in API response")
109
+ return pd.DataFrame()
110
+
111
+ except Exception as e:
112
+ print(f"Error occurred: {str(e)}")
113
+ return pd.DataFrame()
114
+
115
+ def _fetch_income_statement(self) -> pd.DataFrame:
116
+ """
117
+ Get stock income statement data from East Money API
118
+ """
119
+ try:
120
+ # API endpoint and parameters
121
+ api_url = "https://datacenter-web.eastmoney.com/api/data/v1/get"
122
+ params = {
123
+ "reportName": "RPT_DMSK_FN_INCOME",
124
+ "filter": f'(SECURITY_CODE="{self.symbol}")',
125
+ "pageNumber": "1",
126
+ "pageSize": "1000",
127
+ "sortColumns": "REPORT_DATE",
128
+ "sortTypes": "-1",
129
+ "columns": ",".join(self._income_statement_rename_map.keys()),
130
+ }
131
+
132
+ # Fetch data from API
133
+ response = requests.get(api_url, params=params)
134
+ response.raise_for_status()
135
+ data = response.json()
136
+
137
+ # Extract the actual data
138
+ if data.get("result") and data["result"].get("data"):
139
+ df = pd.DataFrame(data["result"]["data"])
140
+ df.rename(columns=self._income_statement_rename_map, inplace=True)
141
+ return df
142
+ else:
143
+ print("No income statement data found in API response")
144
+ return pd.DataFrame()
145
+
146
+ except Exception as e:
147
+ print(f"Error occurred: {str(e)}")
148
+ return pd.DataFrame()
149
+
150
+ def _fetch_cash_flow(self) -> pd.DataFrame:
151
+ """
152
+ Get stock cash flow statement data from East Money API
153
+ """
154
+ try:
155
+ # API endpoint and parameters
156
+ api_url = "https://datacenter-web.eastmoney.com/api/data/v1/get"
157
+ params = {
158
+ "reportName": "RPT_DMSK_FN_CASHFLOW",
159
+ "filter": f'(SECURITY_CODE="{self.symbol}")',
160
+ "pageNumber": "1",
161
+ "pageSize": "1000",
162
+ "sortColumns": "REPORT_DATE",
163
+ "sortTypes": "-1",
164
+ "columns": ",".join(self._cash_flow_rename_map.keys()),
165
+ }
166
+
167
+ # Fetch data from API
168
+ response = requests.get(api_url, params=params)
169
+ response.raise_for_status()
170
+ data = response.json()
171
+
172
+ # Extract the actual data
173
+ if data.get("result") and data["result"].get("data"):
174
+ df = pd.DataFrame(data["result"]["data"])
175
+ df.rename(columns=self._cash_flow_rename_map, inplace=True)
176
+ return df
177
+ else:
178
+ print("No cash flow statement data found in API response")
179
+ return pd.DataFrame()
180
+
181
+ except Exception as e:
182
+ print(f"Error occurred: {str(e)}")
183
+ return pd.DataFrame()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: akshare-one
3
- Version: 0.3.5.1
3
+ Version: 0.3.6
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
@@ -1,8 +1,11 @@
1
1
  akshare_one/__init__.py,sha256=htgTumncxiGHqXMgqmBuIQXoPBcOnwcTjCg02Ydr73I,6524
2
2
  akshare_one/indicators.py,sha256=x3Amff9CG_GvQpA-sqGfFwEAIvaaXlBxDfzTxD05taQ,12533
3
+ akshare_one/eastmoney/client.py,sha256=SSMB4oupaCns5hxtSwxaX-UE_uOrxZEGxqUiC3BT-4k,2794
4
+ akshare_one/eastmoney/utils.py,sha256=fATw0L5SW14wHWXlJ4IFEqnSsSBMT8MYGevxo7Kf1nY,2935
3
5
  akshare_one/modules/cache.py,sha256=_3n35rt9xJfQzZSV6JZ6bGzf2VnqTmLfe49WXk4c9K8,867
4
6
  akshare_one/modules/utils.py,sha256=msHqsjWSRULbX-3Bnit1p26a4a7MOEuNfkPSaECXr4k,333
5
7
  akshare_one/modules/financial/base.py,sha256=TG3ncf3rXfgWCk4qUORN01uxT1SgLWiyjkt5Jb9eoxo,688
8
+ akshare_one/modules/financial/eastmoney_direct.py,sha256=BwiUWi3X24qbtrQv5ht2Lj6crgFrhdcgW4Aa53ZFEOg,6725
6
9
  akshare_one/modules/financial/factory.py,sha256=9xR_uKt7n8dndYUxEGDDL65LXnbm-edtTLdhF0Bfyro,1468
7
10
  akshare_one/modules/financial/sina.py,sha256=c6rSxCVNU6h-7XWSiqPHDN_XAhRdGHdqI9Haruy3mDs,12801
8
11
  akshare_one/modules/historical/base.py,sha256=kDy76OJUp-LIddsC23YAQdf4Q_YGCrnZ8AvU4xRzQsI,1286
@@ -29,8 +32,8 @@ akshare_one/modules/realtime/eastmoney.py,sha256=6acJeIdrvkW4ZqM9CALithlx85QSogr
29
32
  akshare_one/modules/realtime/eastmoney_direct.py,sha256=A2ScBRfIP6n_BxQ6muB26AEykIvTG7Mt3BDAZMyugkg,1236
30
33
  akshare_one/modules/realtime/factory.py,sha256=_7jBDgqWqkt5xTTT1SpZoUHM9IpMRpcUQeyyCglM5z0,1528
31
34
  akshare_one/modules/realtime/xueqiu.py,sha256=CHTN5VUwo24H-2EGKQkN8oqr3MWjDi-7DpvQEDyPlls,2196
32
- akshare_one-0.3.5.1.dist-info/licenses/LICENSE,sha256=3bqxoD7aU4QS7kpNtQmRd4MikxXe6Gtm_DrojyFHGAc,1087
33
- akshare_one-0.3.5.1.dist-info/METADATA,sha256=BwuanrNYHYV1nATF_Z8ixF93Y3fNW9liB4ygJnKgo-E,2274
34
- akshare_one-0.3.5.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
35
- akshare_one-0.3.5.1.dist-info/top_level.txt,sha256=kNiucyLVAGa89wmUSpXbBLWD7pF_RuahuiaOfLHZSyw,12
36
- akshare_one-0.3.5.1.dist-info/RECORD,,
35
+ akshare_one-0.3.6.dist-info/licenses/LICENSE,sha256=3bqxoD7aU4QS7kpNtQmRd4MikxXe6Gtm_DrojyFHGAc,1087
36
+ akshare_one-0.3.6.dist-info/METADATA,sha256=OfOSB9aFz49VnqjJpyHwocEmCAbSLMeC3YoPTNpkwzo,2272
37
+ akshare_one-0.3.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
38
+ akshare_one-0.3.6.dist-info/top_level.txt,sha256=kNiucyLVAGa89wmUSpXbBLWD7pF_RuahuiaOfLHZSyw,12
39
+ akshare_one-0.3.6.dist-info/RECORD,,