Skip to content

Commit 867b4fc

Browse files
author
finanalyzer
authored
Merge pull request #10 from shugaoye/master
Added ak_equity_ownership
2 parents 8572993 + ef685f0 commit 867b4fc

20 files changed

+458
-349
lines changed

openbb_akshare/__init__.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from openbb_akshare.models.equity_quote import AKShareEquityQuoteFetcher
1313
from openbb_akshare.models.equity_historical import AKShareEquityHistoricalFetcher
1414
from openbb_akshare.models.equity_profile import AKShareEquityProfileFetcher
15+
from openbb_akshare.models.equity_screener import AKShareEquityScreenerFetcher
1516
from openbb_akshare.models.historical_dividends import AKShareHistoricalDividendsFetcher
1617
from openbb_akshare.models.income_statement import AKShareIncomeStatementFetcher
1718
from openbb_akshare.models.price_performance import AKSharePricePerformanceFetcher
@@ -21,9 +22,7 @@
2122
provider = Provider(
2223
name="akshare",
2324
description="Data provider for openbb-akshare.",
24-
# Only add 'credentials' if they are needed.
25-
# For multiple login details, list them all here.
26-
# credentials=["api_key"],
25+
credentials=["api_key"],
2726
website="https://akshare.akfamily.xyz/",
2827
# Here, we list out the fetchers showing what our provider can get.
2928
# The dictionary key is the fetcher's name, used in the `router.py`.
@@ -37,6 +36,7 @@
3736
"EquityQuote": AKShareEquityQuoteFetcher,
3837
"EquityHistorical": AKShareEquityHistoricalFetcher,
3938
"EquityInfo": AKShareEquityProfileFetcher,
39+
"EquityScreener": AKShareEquityScreenerFetcher,
4040
"HistoricalDividends": AKShareHistoricalDividendsFetcher,
4141
"IncomeStatement": AKShareIncomeStatementFetcher,
4242
"PricePerformance": AKSharePricePerformanceFetcher,

openbb_akshare/models/balance_sheet.py

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ class AKShareBalanceSheetQueryParams(BalanceSheetQueryParams):
3333
limit: Optional[int] = Field(
3434
default=5,
3535
description=QUERY_DESCRIPTIONS.get("limit", ""),
36-
le=5,
3736
)
3837
use_cache: bool = Field(
3938
default=True,
@@ -47,11 +46,24 @@ class AKShareBalanceSheetData(BalanceSheetData):
4746
__alias_dict__ = {
4847
"period_ending": "REPORT_DATE",
4948
"fiscal_period": "REPORT_TYPE",
50-
"totalEquity": "TOTAL_EQUITY",
51-
"totalDebt": "TOTAL_LIABILITIES",
52-
"totalAssets": "TOTAL_ASSETS"
49+
"股东权益": "TOTAL_EQUITY",
50+
"总负债": "TOTAL_LIABILITIES",
51+
"总资产": "TOTAL_ASSETS"
5352
}
5453

54+
总权益: Optional[float] = Field(
55+
default=None,
56+
description="总权益.",
57+
)
58+
负债总额: Optional[float] = Field(
59+
default=None,
60+
description="负债总额.",
61+
)
62+
总资产: Optional[float] = Field(
63+
default=None,
64+
description="总资产.",
65+
)
66+
5567
@field_validator("period_ending", mode="before", check_fields=False)
5668
@classmethod
5769
def date_validate(cls, v): # pylint: disable=E0213
@@ -84,7 +96,10 @@ def extract_data(
8496
# pylint: disable=import-outside-toplevel
8597
em_df = get_data(query.symbol, query.period, query.use_cache)
8698

87-
return em_df.to_dict(orient="records")
99+
if query.limit is None:
100+
return em_df.to_dict(orient="records")
101+
else:
102+
return em_df.head(query.limit).to_dict(orient="records")
88103

89104
@staticmethod
90105
def transform_data(

openbb_akshare/models/cash_flow.py

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ class AKShareCashFlowStatementQueryParams(CashFlowStatementQueryParams):
3333
limit: Optional[int] = Field(
3434
default=5,
3535
description=QUERY_DESCRIPTIONS.get("limit", ""),
36-
le=5,
3736
)
3837
use_cache: bool = Field(
3938
default=True,
@@ -48,7 +47,22 @@ class AKShareCashFlowStatementData(CashFlowStatementData):
4847
"period_ending": "REPORT_DATE",
4948
"fiscal_period": "REPORT_TYPE",
5049
"reported_currency": "CURRENCY",
50+
"营业性现金流": "NETCASH_OPERATE",
51+
"投资性现金流": "NETCASH_INVEST",
52+
"融资性现金流": "NETCASH_FINANCE",
5153
}
54+
营业性现金流: Optional[float] = Field(
55+
default=None,
56+
description="营业性现金流.",
57+
)
58+
投资性现金流: Optional[float] = Field(
59+
default=None,
60+
description="投资性现金流.",
61+
)
62+
融资性现金流: Optional[float] = Field(
63+
default=None,
64+
description="融资性现金流.",
65+
)
5266

5367
@field_validator("period_ending", mode="before", check_fields=False)
5468
@classmethod
@@ -82,7 +96,10 @@ def extract_data(
8296
# pylint: disable=import-outside-toplevel
8397
em_df = get_data(query.symbol, query.period, query.use_cache)
8498

85-
return em_df.to_dict(orient="records")
99+
if query.limit is None:
100+
return em_df.to_dict(orient="records")
101+
else:
102+
return em_df.head(query.limit).to_dict(orient="records")
86103

87104
@staticmethod
88105
def transform_data(

openbb_akshare/models/equity_historical.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,10 @@ def extract_data(
104104
) -> List[Dict]:
105105
"""Return the raw data from the AKShare endpoint."""
106106
from openbb_akshare.utils.helpers import ak_download
107+
api_key = credentials.get("akshare_api_key") if credentials else ""
107108

108109
data = ak_download(symbol=query.symbol, start_date=query.start_date, end_date=query.end_date,
109-
period="daily", use_cache=query.use_cache, adjust="")
110+
period="daily", use_cache=query.use_cache, api_key=api_key, adjust="")
110111

111112
if data.empty:
112113
raise EmptyDataError()
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
"""AKShare Equity Ownership Model."""
2+
3+
from datetime import (
4+
date as dateType,
5+
datetime,
6+
)
7+
from typing import Any, Dict, List, Optional
8+
9+
from openbb_core.provider.abstract.fetcher import Fetcher
10+
from openbb_core.provider.standard_models.equity_ownership import (
11+
EquityOwnershipData,
12+
EquityOwnershipQueryParams,
13+
)
14+
from mysharelib.tools import most_recent_quarter
15+
from pydantic import field_validator
16+
17+
18+
class AKShareEquityOwnershipQueryParams(EquityOwnershipQueryParams):
19+
"""AKShare Equity Ownership Query.
20+
21+
Source: https://emweb.securities.eastmoney.com/PC_HSF10/ShareholderResearch/Index?type=web&code=SH688686#sdgd-0
22+
"""
23+
24+
@field_validator("date", mode="before", check_fields=True)
25+
@classmethod
26+
def time_validate(cls, v: str):
27+
"""Validate the date."""
28+
if v is None:
29+
v = dateType.today()
30+
if isinstance(v, str):
31+
base = datetime.strptime(v, "%Y-%m-%d").date()
32+
return most_recent_quarter(base)
33+
return most_recent_quarter(v)
34+
35+
36+
class AKShareEquityOwnershipData(EquityOwnershipData):
37+
"""AKShare Equity Ownership Data."""
38+
39+
40+
class AKShareEquityOwnershipFetcher(
41+
Fetcher[
42+
AKShareEquityOwnershipQueryParams,
43+
List[AKShareEquityOwnershipData],
44+
]
45+
):
46+
"""Transform the query, extract and transform the data from the AKShare endpoints."""
47+
48+
@staticmethod
49+
def transform_query(params: Dict[str, Any]) -> AKShareEquityOwnershipQueryParams:
50+
"""Transform the query params."""
51+
return AKShareEquityOwnershipQueryParams(**params)
52+
53+
@staticmethod
54+
def extract_data(
55+
query: AKShareEquityOwnershipQueryParams,
56+
credentials: Optional[Dict[str, str]],
57+
**kwargs: Any,
58+
) -> List[Dict]:
59+
"""Return the raw data from the AKShare endpoint."""
60+
from openbb_akshare.utils.ak_equity_ownership import stock_gdfx_top_10
61+
62+
return stock_gdfx_top_10(query.symbol, query.date).to_dict(orient="records")
63+
64+
@staticmethod
65+
def transform_data(
66+
query: AKShareEquityOwnershipQueryParams, data: List[Dict], **kwargs: Any
67+
) -> List[AKShareEquityOwnershipData]:
68+
"""Return the transformed data."""
69+
own = [AKShareEquityOwnershipData.model_validate(d) for d in data]
70+
own.sort(key=lambda x: x.filing_date, reverse=True)
71+
return own

openbb_akshare/models/equity_profile.py

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# pylint: disable=unused-argument
44

55
from typing import Any, Dict, List, Optional
6-
from datetime import date as dateType
6+
from datetime import (date as dateType, datetime)
77

88
from openbb_core.provider.abstract.fetcher import Fetcher
99
from openbb_core.provider.standard_models.equity_info import (
@@ -29,10 +29,12 @@ class AKShareEquityProfileData(EquityInfoData):
2929
"""AKShare Equity Profile Data."""
3030

3131
__alias_dict__ = {
32+
"公司名称": "org_name_cn",
33+
"公司简介": "org_cn_introduction",
34+
"主要范围": "main_operation_business",
35+
"成立日期": "established_date",
36+
"上市日期": "listed_date",
3237
"name": "org_name_en",
33-
"org_short_name_cn": "quoteType",
34-
"short_description": "main_operation_business",
35-
"long_description": "org_cn_introduction",
3638
"ceo": "chairman",
3739
"company_url": "org_website",
3840
"business_address": "reg_address_cn",
@@ -43,9 +45,23 @@ class AKShareEquityProfileData(EquityInfoData):
4345
"employees": "staff_num",
4446
"sector": "affiliate_industry",
4547
"industry_category": "operating_scope",
46-
"first_stock_price_date": "listed_date",
4748
}
4849

50+
公司名称: Optional[str] = Field(
51+
description="Alias of org_name_cn.",
52+
default=None,
53+
)
54+
公司简介: Optional[str] = Field(
55+
description="Alias of org_name_cn.",
56+
default=None,
57+
)
58+
主要范围: Optional[str] = Field(
59+
description="Alias of org_name_cn.",
60+
default=None,
61+
)
62+
上市日期: Optional[dateType|None] = Field(
63+
default=None, description="Date of the establishment."
64+
)
4965
org_name_cn: Optional[str] = Field(
5066
description="Chinese name of the asset.",
5167
default=None,
@@ -62,7 +78,7 @@ class AKShareEquityProfileData(EquityInfoData):
6278
description="The number of listed shares outstanding.",
6379
default=None,
6480
)
65-
established_date: Optional[dateType] = Field(
81+
established_date: Optional[dateType|None] = Field(
6682
default=None, description="Date of the establishment."
6783
)
6884
actual_issue_vol: Optional[int] = Field(
@@ -107,16 +123,20 @@ def validate_established_date(cls, v):
107123
# pylint: disable=import-outside-toplevel
108124
from datetime import timezone # noqa
109125
from openbb_core.provider.utils.helpers import safe_fromtimestamp # noqa
126+
if pd.isna(v):
127+
return None
110128

111129
return safe_fromtimestamp(get_timestamp(v), tz=timezone.utc).date() if v else None
112130

113-
@field_validator("first_stock_price_date", mode="before", check_fields=False)
131+
@field_validator("上市日期", mode="before", check_fields=False)
114132
@classmethod
115133
def validate_first_trade_date(cls, v):
116134
"""Validate first stock price date."""
117135
# pylint: disable=import-outside-toplevel
118136
from datetime import timezone # noqa
119137
from openbb_core.provider.utils.helpers import safe_fromtimestamp # noqa
138+
if pd.isna(v):
139+
return None
120140

121141
return safe_fromtimestamp(get_timestamp(v), tz=timezone.utc).date() if v else None
122142

@@ -144,24 +164,26 @@ async def aextract_data(
144164
from openbb_core.provider.utils.errors import EmptyDataError
145165
from warnings import warn
146166

167+
api_key = credentials.get("akshare_api_key") if credentials else ""
168+
147169
symbols = query.symbol.split(",")
148170
results = []
149171
messages: list = []
150172

151-
async def get_one(symbol):
173+
async def get_one(symbol, api_key: str, use_cache: bool = True):
152174
from openbb_akshare.utils.fetch_equity_info import fetch_equity_info
153175
"""Get the data for one ticker symbol."""
154176
try:
155177
result: dict = {}
156-
result = fetch_equity_info(symbol).to_dict(orient="records")[0]
178+
result = fetch_equity_info(symbol, api_key=api_key, use_cache=use_cache).to_dict(orient="records")[0]
157179
if result:
158180
results.append(result)
159181
except Exception as e:
160182
messages.append(
161183
f"Error getting data for {symbol} -> {e.__class__.__name__}: {e}"
162184
)
163185

164-
tasks = [get_one(symbol) for symbol in symbols]
186+
tasks = [get_one(symbol, api_key=api_key, use_cache=query.use_cache) for symbol in symbols]
165187

166188
await asyncio.gather(*tasks)
167189

0 commit comments

Comments
 (0)