Skip to content

Commit c35d825

Browse files
authored
Merge pull request #16 from shugaoye/master
chore: update dependencies and version for openbb-akshare
2 parents 2736727 + 4558b33 commit c35d825

22 files changed

+4952
-2887
lines changed

openbb_akshare/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from openbb_akshare.models.equity_historical import AKShareEquityHistoricalFetcher
1414
from openbb_akshare.models.equity_profile import AKShareEquityProfileFetcher
1515
from openbb_akshare.models.equity_screener import AKShareEquityScreenerFetcher
16+
from openbb_akshare.models.equity_search import AKShareEquitySearchFetcher
1617
from openbb_akshare.models.historical_dividends import AKShareHistoricalDividendsFetcher
1718
from openbb_akshare.models.income_statement import AKShareIncomeStatementFetcher
1819
from openbb_akshare.models.key_metrics import AKShareKeyMetricsFetcher
@@ -38,6 +39,7 @@
3839
"EquityHistorical": AKShareEquityHistoricalFetcher,
3940
"EquityInfo": AKShareEquityProfileFetcher,
4041
"EquityScreener": AKShareEquityScreenerFetcher,
42+
"EquitySearch": AKShareEquitySearchFetcher,
4143
"HistoricalDividends": AKShareHistoricalDividendsFetcher,
4244
"IncomeStatement": AKShareIncomeStatementFetcher,
4345
"KeyMetrics": AKShareKeyMetricsFetcher,

openbb_akshare/models/balance_sheet.py

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,13 @@
1313
from openbb_core.provider.utils.descriptions import QUERY_DESCRIPTIONS
1414
from pydantic import Field, field_validator
1515

16+
import logging
17+
from openbb_akshare import project_name
18+
from mysharelib.tools import setup_logger
19+
20+
setup_logger(project_name)
21+
logger = logging.getLogger(__name__)
22+
1623

1724
class AKShareBalanceSheetQueryParams(BalanceSheetQueryParams):
1825
"""AKShare Balance Sheet Query.
@@ -93,13 +100,10 @@ def extract_data(
93100
**kwargs: Any,
94101
) -> list[dict]:
95102
"""Extract the data from the AKShare endpoints."""
103+
api_key = credentials.get("akshare_api_key") if credentials else ""
96104
# pylint: disable=import-outside-toplevel
97-
em_df = get_data(query.symbol, query.period, query.use_cache)
98-
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")
105+
em_df = get_data(query.symbol, query.period, query.use_cache, api_key=api_key, limit=query.limit)
106+
return em_df.head(query.limit).to_dict(orient="records")
103107

104108
@staticmethod
105109
def transform_data(
@@ -110,21 +114,15 @@ def transform_data(
110114
"""Transform the data."""
111115
return [AKShareBalanceSheetData.model_validate(d) for d in data]
112116

113-
def get_data(symbol: str, period: str = "annual", use_cache: bool = True) -> pd.DataFrame:
117+
def get_data(symbol: str, period: Literal["annual", "quarter"] = "annual", use_cache: bool = True, api_key:str="", limit:int = 5) -> pd.DataFrame:
114118
from openbb_akshare import project_name
115119
from mysharelib.blob_cache import BlobCache
116120
cache = BlobCache(table_name="balance_sheet", project=project_name)
117-
return cache.load_cached_data(symbol, period, use_cache, get_ak_data)
118-
119-
def get_ak_data(symbol: str, period: str = "annual", api_key : Optional[str] = "") -> pd.DataFrame:
120-
import akshare as ak
121-
from openbb_akshare.utils.helpers import normalize_symbol
122-
symbol_b, symbol_f, market = normalize_symbol(symbol)
123-
symbol_em = f"{market}{symbol_b}"
124-
125-
if period == "annual":
126-
return ak.stock_balance_sheet_by_yearly_em(symbol=symbol_em)
127-
elif period == "quarter":
128-
return ak.stock_balance_sheet_by_report_em(symbol=symbol_em)
129-
else:
130-
raise ValueError("Invalid period. Please use 'annual' or 'quarter'.")
121+
logger.info(f"Fetching balance sheet data for {symbol} with limit {limit} and use_cache={use_cache}")
122+
return cache.load_cached_data(symbol, period, use_cache, get_ak_data, api_key, limit)
123+
124+
def get_ak_data(symbol: str, period: Literal["annual", "quarter"] = "annual", api_key : Optional[str] = "", limit:int = 5) -> pd.DataFrame:
125+
from openbb_akshare.utils.ak_balance_sheet import ak_stock_balance_sheet
126+
127+
logger.info(f"Getting balance sheet data for {symbol} with limit {limit}")
128+
return ak_stock_balance_sheet(symbol, limit, period)

openbb_akshare/models/cash_flow.py

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@
66
from typing import Any, Literal, Optional
77

88
from openbb_core.provider.abstract.fetcher import Fetcher
9+
import logging
10+
from openbb_akshare import project_name
11+
from mysharelib.tools import setup_logger
12+
13+
setup_logger(project_name)
14+
logger = logging.getLogger(__name__)
915
from openbb_core.provider.standard_models.cash_flow import (
1016
CashFlowStatementData,
1117
CashFlowStatementQueryParams,
@@ -94,7 +100,8 @@ def extract_data(
94100
) -> list[dict]:
95101
"""Extract the data from the AKShare endpoints."""
96102
# pylint: disable=import-outside-toplevel
97-
em_df = get_data(query.symbol, query.period, query.use_cache)
103+
api_key = credentials.get("akshare_api_key") if credentials else ""
104+
em_df = get_data(query.symbol, query.period, query.use_cache, api_key=api_key, limit=query.limit)
98105

99106
if query.limit is None:
100107
return em_df.to_dict(orient="records")
@@ -110,22 +117,15 @@ def transform_data(
110117
"""Transform the data."""
111118
return [AKShareCashFlowStatementData.model_validate(d) for d in data]
112119

113-
def get_data(symbol: str, period: str = "annual", use_cache: bool = True) -> pd.DataFrame:
120+
def get_data(symbol: str, period: Literal["annual", "quarter"] = "annual", use_cache: bool = True, api_key:str="", limit:int = 5) -> pd.DataFrame:
114121
from openbb_akshare import project_name
115122
from mysharelib.blob_cache import BlobCache
116-
117123
cache = BlobCache(table_name="cash_flow", project=project_name)
118-
return cache.load_cached_data(symbol, period, use_cache, get_ak_data)
119-
120-
def get_ak_data(symbol: str, period: str = "annual", api_key : Optional[str] = "") -> pd.DataFrame:
121-
import akshare as ak
122-
from openbb_akshare.utils.helpers import normalize_symbol
123-
symbol_b, symbol_f, market = normalize_symbol(symbol)
124-
symbol_em = f"{market}{symbol_b}"
125-
126-
if period == "annual":
127-
return ak.stock_cash_flow_sheet_by_yearly_em(symbol=symbol_em)
128-
elif period == "quarter":
129-
return ak.stock_cash_flow_sheet_by_report_em(symbol=symbol_em)
130-
else:
131-
raise ValueError("Invalid period. Please use 'annual' or 'quarter'.")
124+
logger.info(f"Fetching cash flow data for {symbol} with limit {limit} and use_cache={use_cache}")
125+
return cache.load_cached_data(symbol, period, use_cache, get_ak_data, api_key, limit)
126+
127+
def get_ak_data(symbol: str, period: Literal["annual", "quarter"] = "annual", api_key : Optional[str] = "", limit:int = 5) -> pd.DataFrame:
128+
from openbb_akshare.utils.ak_cash_flow import ak_stock_cash_flow
129+
130+
logger.info(f"Getting cash flow data for {symbol} with limit {limit}")
131+
return ak_stock_cash_flow(symbol, limit, period)

openbb_akshare/models/company_news.py

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -62,22 +62,34 @@ async def aextract_data(
6262
# pylint: disable=import-outside-toplevel
6363
import asyncio # noqa
6464
from openbb_core.provider.utils.errors import EmptyDataError
65-
from openbb_core.provider.utils.helpers import get_requests_session
6665
import akshare as ak
66+
from mysharelib.tools import normalize_symbol
6767

6868
results: list = []
6969
symbols = query.symbol.split(",") # type: ignore
7070
async def get_one(symbol):
71-
data = ak.stock_news_em(symbol)
72-
for idx, d in data.iterrows():
73-
new_content: dict = {}
74-
new_content["text"] = d["新闻内容"]
75-
new_content["url"] = d["新闻链接"]
76-
new_content["source"] = d["文章来源"]
77-
new_content["title"] = d["新闻标题"]
78-
new_content["date"] = d["发布时间"]
79-
80-
results.append(new_content)
71+
from mysharelib.sina.scrape_hk_stock_news import scrape_hk_stock_news
72+
from mysharelib.em.stock_info_em import stock_info_em
73+
74+
symbol_b, _, market = normalize_symbol(symbol)
75+
if market == "HK":
76+
data = scrape_hk_stock_news(symbol_b)
77+
if data is not None:
78+
for d in data.to_dict(orient='records'):
79+
new_content: dict = {}
80+
new_content["date"] = d["date"]
81+
new_content["title"] = d["title"]
82+
new_content["url"] = d["url"]
83+
results.append(new_content)
84+
else:
85+
data = stock_info_em(symbol)
86+
for idx, d in data.iterrows():
87+
new_content: dict = {}
88+
new_content["url"] = d["新闻链接"]
89+
new_content["title"] = d["新闻标题"]
90+
new_content["date"] = d["发布时间"]
91+
92+
results.append(new_content)
8193

8294
tasks = [get_one(symbol) for symbol in symbols]
8395

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
"""AKShare Equity Search Model."""
2+
3+
from typing import Any, Dict, List, Optional
4+
5+
from openbb_core.provider.abstract.fetcher import Fetcher
6+
from openbb_core.provider.standard_models.equity_search import (
7+
EquitySearchData,
8+
EquitySearchQueryParams,
9+
)
10+
from openbb_core.provider.utils.descriptions import (
11+
DATA_DESCRIPTIONS,
12+
QUERY_DESCRIPTIONS,
13+
)
14+
from pydantic import Field
15+
16+
import logging
17+
from openbb_akshare import project_name
18+
from mysharelib.tools import setup_logger
19+
20+
setup_logger(project_name)
21+
logger = logging.getLogger(__name__)
22+
23+
24+
class AKShareEquitySearchQueryParams(EquitySearchQueryParams):
25+
"""AKShare Equity Search Query.
26+
"""
27+
28+
use_cache: bool = Field(
29+
default=True,
30+
description="Whether to use a cached request. The quote is cached for one hour.",
31+
)
32+
limit: Optional[int] = Field(
33+
default=10000,
34+
description=QUERY_DESCRIPTIONS.get("limit", ""),
35+
)
36+
37+
38+
class AKShareEquitySearchData(EquitySearchData):
39+
"""AKShare Equity Search Data."""
40+
41+
42+
class AKShareEquitySearchFetcher(
43+
Fetcher[
44+
AKShareEquitySearchQueryParams,
45+
List[AKShareEquitySearchData],
46+
]
47+
):
48+
"""Transform the query, extract and transform the data from the AKShare endpoints."""
49+
50+
@staticmethod
51+
def transform_query(params: Dict[str, Any]) -> AKShareEquitySearchQueryParams:
52+
"""Transform the query."""
53+
return AKShareEquitySearchQueryParams(**params)
54+
55+
@staticmethod
56+
async def aextract_data(
57+
query: AKShareEquitySearchQueryParams, # pylint: disable=unused-argument
58+
credentials: Optional[Dict[str, str]],
59+
**kwargs: Any,
60+
) -> List[Dict]:
61+
"""Return the raw data from the AKShare endpoint."""
62+
63+
from openbb_akshare.utils.ak_equity_search import get_symbols
64+
api_key = credentials.get("akshare_api_key") if credentials else ""
65+
data = get_symbols(query.use_cache, api_key=api_key)
66+
if query.limit: data = data.head(query.limit)
67+
68+
return data.to_dict(orient="records")
69+
70+
@staticmethod
71+
def transform_data(
72+
query: AKShareEquitySearchQueryParams, data: Dict, **kwargs: Any
73+
) -> List[AKShareEquitySearchData]:
74+
"""Transform the data to the standard format."""
75+
76+
if query.query:
77+
filtered = [
78+
d for d in data
79+
if query.query in d.get('name', '') or query.query in d.get('symbol', '')
80+
]
81+
logger.info(f"Searching for {query.query} and found {len(filtered)} results.")
82+
return [AKShareEquitySearchData.model_validate(d) for d in filtered]
83+
84+
return [AKShareEquitySearchData.model_validate(d) for d in data]

openbb_akshare/models/income_statement.py

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@
99
from typing import Any, Dict, List, Literal, Optional
1010

1111
from openbb_core.provider.abstract.fetcher import Fetcher
12+
import logging
13+
from openbb_akshare import project_name
14+
from mysharelib.tools import setup_logger
15+
16+
setup_logger(project_name)
17+
logger = logging.getLogger(__name__)
1218
from openbb_core.provider.standard_models.income_statement import (
1319
IncomeStatementData,
1420
IncomeStatementQueryParams,
@@ -98,8 +104,9 @@ async def extract_data(
98104
**kwargs: Any,
99105
) -> List[Dict]:
100106
"""Return the raw data from the AKShare endpoint."""
107+
api_key = credentials.get("akshare_api_key") if credentials else ""
101108

102-
em_df = get_data(query.symbol, query.period, query.use_cache)
109+
em_df = get_data(query.symbol, query.period, query.use_cache, api_key=api_key, limit=query.limit)
103110

104111
if query.limit is None:
105112
return em_df.to_dict(orient="records")
@@ -116,21 +123,15 @@ def transform_data(
116123
result.pop("cik", None)
117124
return [AKShareIncomeStatementData.model_validate(d) for d in data]
118125

119-
def get_data(symbol: str, period: str = "annual", use_cache: bool = True) -> pd.DataFrame:
126+
def get_data(symbol: str, period: Literal["annual", "quarter"] = "annual", use_cache: bool = True, api_key:str="", limit:int = 5) -> pd.DataFrame:
120127
from openbb_akshare import project_name
121128
from mysharelib.blob_cache import BlobCache
122129
cache = BlobCache(table_name="income_statement", project=project_name)
123-
return cache.load_cached_data(symbol, period, use_cache, get_income_statement)
124-
125-
def get_income_statement(symbol: str, period: str = "annual", api_key : Optional[str] = "") -> pd.DataFrame:
126-
import akshare as ak
127-
from openbb_akshare.utils.helpers import normalize_symbol
128-
symbol_b, symbol_f, market = normalize_symbol(symbol)
129-
symbol_em = f"{market}{symbol_b}"
130-
131-
if period == "annual":
132-
return ak.stock_profit_sheet_by_yearly_em(symbol=symbol_em)
133-
elif period == "quarter":
134-
return ak.stock_profit_sheet_by_report_em(symbol=symbol_em)
135-
else:
136-
raise ValueError("Invalid period. Please use 'annual' or 'quarter'.")
130+
logger.info(f"Fetching income statement data for {symbol} with limit {limit} and use_cache={use_cache}")
131+
return cache.load_cached_data(symbol, period, use_cache, get_income_statement, api_key, limit)
132+
133+
def get_income_statement(symbol: str, period: Literal["annual", "quarter"] = "annual", api_key : Optional[str] = "", limit:int = 5) -> pd.DataFrame:
134+
from openbb_akshare.utils.ak_income_statement import ak_stock_income_statement
135+
136+
logger.info(f"Getting income statement data for {symbol} with limit {limit}")
137+
return ak_stock_income_statement(symbol, limit, period)

openbb_akshare/router.py

Lines changed: 4 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -13,48 +13,13 @@
1313

1414
router = Router(prefix="")
1515

16-
@register_widget({
17-
"name": "Company Facts",
18-
"description": "Get key company information including name, CIK, market cap, total employees, website URL, and more.",
19-
"category": "Equity",
20-
"subcategory": "Company Info",
21-
"type": "table",
22-
"widgetId": "company_facts",
23-
"endpoint": "company_facts",
24-
"gridData": {
25-
"w": 10,
26-
"h": 12
27-
},
28-
"params": [
29-
{
30-
"type": "endpoint",
31-
"paramName": "ticker",
32-
"label": "Symbol",
33-
"value": "600325",
34-
"description": "Ticker to get company facts for (Free tier: AAPL, MSFT, TSLA)",
35-
"optionsEndpoint": "/stock_tickers"
36-
}
37-
]
38-
})
3916
@router.command(methods=["GET"])
40-
async def company_facts(symbol: str = "600325") -> OBBject[dict]:
17+
async def get_example(symbol: str = "AAPL") -> OBBject[dict]:
4118
"""Get options data."""
42-
import numpy as np
43-
import pandas as pd
19+
base_url = "https://www.cboe.com/education/tools/trade-optimizer/symbol-info"
4420

45-
from openbb_akshare.utils.fetch_equity_info import fetch_equity_info
46-
from mysharelib.tools import normalize_symbol
47-
48-
user_setting = UserService.read_from_file()
49-
credentials = user_setting.credentials
50-
api_key = credentials.akshare_api_key.get_secret_value()
51-
df = fetch_equity_info(symbol, api_key=api_key, use_cache=True)
52-
df.set_index('symbol', inplace=True)
53-
54-
_, symbol_f, _ = normalize_symbol(symbol)
55-
data = df.T.to_dict(orient="dict")[symbol_f]
56-
57-
return OBBject(results=data)
21+
response = requests.get(base_url + f"?symbol={symbol}", timeout=5).json()
22+
return OBBject(results=response["details"])
5823

5924

6025
@router.command(methods=["POST"])

0 commit comments

Comments
 (0)