akshare-one 0.1.2__py3-none-any.whl → 0.2.0__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.
- akshare_one/__init__.py +2 -3
- akshare_one/financial.py +7 -4
- akshare_one/insider.py +6 -5
- akshare_one/modules/cache.py +9 -0
- akshare_one/modules/financial/base.py +41 -0
- akshare_one/modules/financial/factory.py +44 -0
- akshare_one/{adapters → modules/financial}/sina.py +30 -195
- akshare_one/modules/historical/base.py +64 -0
- akshare_one/modules/historical/eastmoney.py +242 -0
- akshare_one/modules/historical/factory.py +46 -0
- akshare_one/modules/historical/sina.py +219 -0
- akshare_one/modules/insider/base.py +78 -0
- akshare_one/modules/insider/factory.py +44 -0
- akshare_one/{adapters → modules/insider}/xueqiu.py +21 -11
- akshare_one/modules/news/base.py +51 -0
- akshare_one/modules/news/eastmoney.py +48 -0
- akshare_one/modules/news/factory.py +44 -0
- akshare_one/modules/realtime/base.py +68 -0
- akshare_one/modules/realtime/eastmoney.py +58 -0
- akshare_one/modules/realtime/factory.py +46 -0
- akshare_one/modules/realtime/xueqiu.py +61 -0
- akshare_one/modules/utils.py +10 -0
- akshare_one/news.py +3 -4
- akshare_one/stock.py +18 -26
- {akshare_one-0.1.2.dist-info → akshare_one-0.2.0.dist-info}/METADATA +2 -2
- akshare_one-0.2.0.dist-info/RECORD +29 -0
- {akshare_one-0.1.2.dist-info → akshare_one-0.2.0.dist-info}/WHEEL +1 -1
- akshare_one/adapters/__init__.py +0 -7
- akshare_one/adapters/cache/cache.py +0 -9
- akshare_one/adapters/eastmoney.py +0 -342
- akshare_one-0.1.2.dist-info/RECORD +0 -15
- {akshare_one-0.1.2.dist-info → akshare_one-0.2.0.dist-info}/licenses/LICENSE +0 -0
- {akshare_one-0.1.2.dist-info → akshare_one-0.2.0.dist-info}/top_level.txt +0 -0
akshare_one/__init__.py
CHANGED
@@ -7,12 +7,11 @@ Provides standardized access to various financial data sources with:
|
|
7
7
|
|
8
8
|
Example:
|
9
9
|
>>> from akshare_one import get_hist_data, get_realtime_data
|
10
|
+
>>> # 获取股票历史数据
|
10
11
|
>>> df = get_hist_data("600000", interval="day")
|
11
12
|
>>> print(df.head())
|
12
|
-
>>> #
|
13
|
+
>>> # 获取股票实时数据
|
13
14
|
>>> df = get_realtime_data(symbol="600000")
|
14
|
-
>>> # 获取所有股票实时数据
|
15
|
-
>>> df = get_realtime_data()
|
16
15
|
"""
|
17
16
|
|
18
17
|
from .stock import get_hist_data, get_realtime_data
|
akshare_one/financial.py
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
"""
|
5
5
|
|
6
6
|
import pandas as pd
|
7
|
-
from .
|
7
|
+
from akshare_one.modules.financial.factory import FinancialDataFactory
|
8
8
|
|
9
9
|
|
10
10
|
def get_balance_sheet(symbol: str, source: str = "sina") -> "pd.DataFrame":
|
@@ -15,7 +15,8 @@ def get_balance_sheet(symbol: str, source: str = "sina") -> "pd.DataFrame":
|
|
15
15
|
source: 数据源 ("sina")
|
16
16
|
"""
|
17
17
|
if source == "sina":
|
18
|
-
|
18
|
+
provider = FinancialDataFactory.get_provider(source, symbol=symbol)
|
19
|
+
return provider.get_balance_sheet()
|
19
20
|
raise ValueError(f"Unsupported data source: {source}")
|
20
21
|
|
21
22
|
|
@@ -27,7 +28,8 @@ def get_income_statement(symbol: str, source: str = "sina") -> "pd.DataFrame":
|
|
27
28
|
source: 数据源 ("sina")
|
28
29
|
"""
|
29
30
|
if source == "sina":
|
30
|
-
|
31
|
+
provider = FinancialDataFactory.get_provider(source, symbol=symbol)
|
32
|
+
return provider.get_income_statement()
|
31
33
|
raise ValueError(f"Unsupported data source: {source}")
|
32
34
|
|
33
35
|
|
@@ -39,5 +41,6 @@ def get_cash_flow(symbol: str, source: str = "sina") -> "pd.DataFrame":
|
|
39
41
|
source: 数据源 ("sina")
|
40
42
|
"""
|
41
43
|
if source == "sina":
|
42
|
-
|
44
|
+
provider = FinancialDataFactory.get_provider(source, symbol=symbol)
|
45
|
+
return provider.get_cash_flow()
|
43
46
|
raise ValueError(f"Unsupported data source: {source}")
|
akshare_one/insider.py
CHANGED
@@ -5,10 +5,12 @@
|
|
5
5
|
|
6
6
|
from typing import Optional
|
7
7
|
import pandas as pd
|
8
|
-
from .
|
8
|
+
from .modules.insider.factory import InsiderDataFactory
|
9
9
|
|
10
10
|
|
11
|
-
def get_inner_trade_data(
|
11
|
+
def get_inner_trade_data(
|
12
|
+
symbol: Optional[str] = None, source: str = "xueqiu"
|
13
|
+
) -> "pd.DataFrame":
|
12
14
|
"""获取雪球内部交易数据
|
13
15
|
|
14
16
|
Args:
|
@@ -30,6 +32,5 @@ def get_inner_trade_data(source: str = "xueqiu", symbol: Optional[str] = None) -
|
|
30
32
|
- transaction_value: 交易金额(变动股数*成交均价)
|
31
33
|
- shares_owned_before_transaction: 变动前持股数
|
32
34
|
"""
|
33
|
-
|
34
|
-
|
35
|
-
raise ValueError(f"Unsupported data source: {source}")
|
35
|
+
provider = InsiderDataFactory.get_provider(source, symbol=symbol)
|
36
|
+
return provider.get_inner_trade_data()
|
@@ -0,0 +1,9 @@
|
|
1
|
+
from cachetools import TTLCache
|
2
|
+
|
3
|
+
# 缓存配置
|
4
|
+
CACHE_CONFIG = {
|
5
|
+
"hist_data_cache": TTLCache(maxsize=1000, ttl=3600), # 历史数据缓存1小时
|
6
|
+
"realtime_cache": TTLCache(maxsize=500, ttl=60), # 实时数据缓存1分钟
|
7
|
+
"news_cache": TTLCache(maxsize=500, ttl=3600),
|
8
|
+
"financial_cache": TTLCache(maxsize=500, ttl=86400), # 财务数据缓存24小时
|
9
|
+
}
|
@@ -0,0 +1,41 @@
|
|
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
|
@@ -0,0 +1,44 @@
|
|
1
|
+
from .sina import SinaFinancialReport
|
2
|
+
from .base import FinancialDataProvider
|
3
|
+
|
4
|
+
|
5
|
+
class FinancialDataFactory:
|
6
|
+
"""
|
7
|
+
Factory class for creating financial data providers
|
8
|
+
"""
|
9
|
+
|
10
|
+
_providers = {
|
11
|
+
"sina": SinaFinancialReport,
|
12
|
+
}
|
13
|
+
|
14
|
+
@classmethod
|
15
|
+
def get_provider(cls, provider_name: str, **kwargs) -> FinancialDataProvider:
|
16
|
+
"""
|
17
|
+
Get a financial data provider by name
|
18
|
+
|
19
|
+
Args:
|
20
|
+
provider_name: Name of the provider (e.g., 'sina')
|
21
|
+
**kwargs: Additional arguments to pass to the provider's constructor
|
22
|
+
|
23
|
+
Returns:
|
24
|
+
FinancialDataProvider: An instance of the requested provider
|
25
|
+
|
26
|
+
Raises:
|
27
|
+
ValueError: If the requested provider is not found
|
28
|
+
"""
|
29
|
+
provider_class = cls._providers.get(provider_name.lower())
|
30
|
+
if not provider_class:
|
31
|
+
raise ValueError(f"Unknown financial data provider: {provider_name}")
|
32
|
+
|
33
|
+
return provider_class(**kwargs)
|
34
|
+
|
35
|
+
@classmethod
|
36
|
+
def register_provider(cls, name: str, provider_class: type):
|
37
|
+
"""
|
38
|
+
Register a new financial data provider
|
39
|
+
|
40
|
+
Args:
|
41
|
+
name: Name to associate with this provider
|
42
|
+
provider_class: The provider class to register
|
43
|
+
"""
|
44
|
+
cls._providers[name.lower()] = provider_class
|
@@ -1,19 +1,24 @@
|
|
1
|
+
from cachetools import cached
|
1
2
|
import pandas as pd
|
2
3
|
import akshare as ak
|
3
|
-
from cachetools import cached
|
4
|
-
from .cache.cache import CACHE_CONFIG
|
5
4
|
|
5
|
+
from akshare_one.modules.cache import CACHE_CONFIG
|
6
|
+
from .base import FinancialDataProvider, validate_financial_data
|
6
7
|
|
7
|
-
class SinaAdapter:
|
8
|
-
"""Adapter for Sina financial data API
|
9
8
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
9
|
+
class SinaFinancialReport(FinancialDataProvider):
|
10
|
+
def __init__(self, symbol: str) -> None:
|
11
|
+
super().__init__(symbol)
|
12
|
+
self.stock = (
|
13
|
+
f"sh{symbol}" if not symbol.startswith(("sh", "sz", "bj")) else symbol
|
14
|
+
)
|
14
15
|
|
15
|
-
@
|
16
|
-
|
16
|
+
@validate_financial_data
|
17
|
+
@cached(
|
18
|
+
CACHE_CONFIG["financial_cache"],
|
19
|
+
key=lambda self, symbol=None: f"sina_balance_{self.symbol}",
|
20
|
+
)
|
21
|
+
def get_balance_sheet(self) -> pd.DataFrame:
|
17
22
|
"""获取资产负债表数据
|
18
23
|
|
19
24
|
Args:
|
@@ -22,12 +27,15 @@ class SinaAdapter:
|
|
22
27
|
Returns:
|
23
28
|
Standardized DataFrame with balance sheet data
|
24
29
|
"""
|
25
|
-
|
26
|
-
raw_df = ak.stock_financial_report_sina(stock=stock, symbol="资产负债表")
|
30
|
+
raw_df = ak.stock_financial_report_sina(stock=self.stock, symbol="资产负债表")
|
27
31
|
return self._clean_balance_data(raw_df)
|
28
32
|
|
29
|
-
@
|
30
|
-
|
33
|
+
@validate_financial_data
|
34
|
+
@cached(
|
35
|
+
CACHE_CONFIG["financial_cache"],
|
36
|
+
key=lambda self, symbol=None: f"sina_income_{self.symbol}",
|
37
|
+
)
|
38
|
+
def get_income_statement(self) -> pd.DataFrame:
|
31
39
|
"""获取利润表数据
|
32
40
|
|
33
41
|
Args:
|
@@ -36,12 +44,15 @@ class SinaAdapter:
|
|
36
44
|
Returns:
|
37
45
|
Standardized DataFrame with income statement data
|
38
46
|
"""
|
39
|
-
|
40
|
-
raw_df = ak.stock_financial_report_sina(stock=stock, symbol="利润表")
|
47
|
+
raw_df = ak.stock_financial_report_sina(stock=self.stock, symbol="利润表")
|
41
48
|
return self._clean_income_data(raw_df)
|
42
49
|
|
43
|
-
@
|
44
|
-
|
50
|
+
@validate_financial_data
|
51
|
+
@cached(
|
52
|
+
CACHE_CONFIG["financial_cache"],
|
53
|
+
key=lambda self, symbol=None: f"sina_cash_{self.symbol}",
|
54
|
+
)
|
55
|
+
def get_cash_flow(self) -> pd.DataFrame:
|
45
56
|
"""获取现金流量表数据
|
46
57
|
|
47
58
|
Args:
|
@@ -50,8 +61,7 @@ class SinaAdapter:
|
|
50
61
|
Returns:
|
51
62
|
Standardized DataFrame with cash flow data
|
52
63
|
"""
|
53
|
-
|
54
|
-
raw_df = ak.stock_financial_report_sina(stock=stock, symbol="现金流量表")
|
64
|
+
raw_df = ak.stock_financial_report_sina(stock=self.stock, symbol="现金流量表")
|
55
65
|
return self._clean_cash_data(raw_df)
|
56
66
|
|
57
67
|
def _clean_cash_data(self, raw_df: pd.DataFrame) -> pd.DataFrame:
|
@@ -199,181 +209,6 @@ class SinaAdapter:
|
|
199
209
|
available_columns = [col for col in required_columns if col in raw_df.columns]
|
200
210
|
return raw_df[available_columns]
|
201
211
|
|
202
|
-
@cached(
|
203
|
-
CACHE_CONFIG["hist_data_cache"],
|
204
|
-
key=lambda self,
|
205
|
-
symbol,
|
206
|
-
interval,
|
207
|
-
interval_multiplier,
|
208
|
-
start_date,
|
209
|
-
end_date,
|
210
|
-
adjust: ("sina", symbol, interval, interval_multiplier, start_date, end_date, adjust),
|
211
|
-
)
|
212
|
-
def get_hist_data(
|
213
|
-
self,
|
214
|
-
symbol: str,
|
215
|
-
interval: str = "day",
|
216
|
-
interval_multiplier: int = 1,
|
217
|
-
start_date: str = "1970-01-01",
|
218
|
-
end_date: str = "2030-12-31",
|
219
|
-
adjust: str = "none",
|
220
|
-
) -> pd.DataFrame:
|
221
|
-
"""获取新浪历史行情数据
|
222
|
-
|
223
|
-
Args:
|
224
|
-
symbol: 股票代码 (如 "600000")
|
225
|
-
interval: 时间粒度 (支持: "minute", "hour", "day", "week", "month", "year")
|
226
|
-
interval_multiplier: 时间间隔倍数 (如: 5分钟数据设为5)
|
227
|
-
start_date: 开始日期 (YYYY-MM-DD)
|
228
|
-
end_date: 结束日期 (YYYY-MM-DD)
|
229
|
-
adjust: 复权类型 ('none','qfq','hfq','qfq-factor','hfq-factor')
|
230
|
-
|
231
|
-
Returns:
|
232
|
-
Standardized DataFrame with OHLCV data
|
233
|
-
"""
|
234
|
-
interval = interval.lower()
|
235
|
-
stock = f"sh{symbol}" if not symbol.startswith(("sh", "sz", "bj")) else symbol
|
236
|
-
|
237
|
-
if interval == "minute":
|
238
|
-
raw_df = ak.stock_zh_a_minute(
|
239
|
-
symbol=stock,
|
240
|
-
period="1",
|
241
|
-
adjust=adjust if adjust != "none" else "",
|
242
|
-
)
|
243
|
-
raw_df = raw_df.rename(columns={"day": "date"})
|
244
|
-
raw_df["date"] = pd.to_datetime(raw_df["date"])
|
245
|
-
raw_df = raw_df.set_index("date")
|
246
|
-
raw_df = (
|
247
|
-
raw_df.resample(f"{interval_multiplier}min")
|
248
|
-
.agg(
|
249
|
-
{
|
250
|
-
"open": "first",
|
251
|
-
"high": "max",
|
252
|
-
"low": "min",
|
253
|
-
"close": "last",
|
254
|
-
"volume": "sum",
|
255
|
-
}
|
256
|
-
)
|
257
|
-
.reset_index()
|
258
|
-
)
|
259
|
-
|
260
|
-
elif interval == "hour":
|
261
|
-
if interval_multiplier < 1:
|
262
|
-
raise ValueError("Hour interval multiplier must be >= 1")
|
263
|
-
|
264
|
-
raw_df = ak.stock_zh_a_minute(
|
265
|
-
symbol=stock,
|
266
|
-
period="60",
|
267
|
-
adjust=adjust if adjust != "none" else "",
|
268
|
-
)
|
269
|
-
raw_df = raw_df.rename(columns={"day": "date"})
|
270
|
-
raw_df["date"] = pd.to_datetime(raw_df["date"])
|
271
|
-
raw_df = raw_df.set_index("date")
|
272
|
-
raw_df = (
|
273
|
-
raw_df.resample(f"{interval_multiplier}h")
|
274
|
-
.agg(
|
275
|
-
{
|
276
|
-
"open": "first",
|
277
|
-
"high": "max",
|
278
|
-
"low": "min",
|
279
|
-
"close": "last",
|
280
|
-
"volume": "sum",
|
281
|
-
}
|
282
|
-
)
|
283
|
-
.reset_index()
|
284
|
-
)
|
285
|
-
|
286
|
-
elif interval in ["day", "week", "month", "year"]:
|
287
|
-
# Convert date format from YYYY-MM-DD to YYYYMMDD
|
288
|
-
start_date = (
|
289
|
-
start_date.replace("-", "") if "-" in start_date else start_date
|
290
|
-
)
|
291
|
-
end_date = end_date.replace("-", "") if "-" in end_date else end_date
|
292
|
-
|
293
|
-
raw_df = ak.stock_zh_a_daily(
|
294
|
-
symbol=stock,
|
295
|
-
start_date=start_date,
|
296
|
-
end_date=end_date,
|
297
|
-
adjust=adjust if adjust != "none" else "",
|
298
|
-
)
|
299
|
-
|
300
|
-
if interval_multiplier > 1:
|
301
|
-
raw_df = self._resample_data(raw_df, interval, interval_multiplier)
|
302
|
-
else:
|
303
|
-
raise ValueError(f"Unsupported interval: {interval}")
|
304
|
-
|
305
|
-
return self._clean_hist_data(raw_df, adjust)
|
306
|
-
|
307
|
-
def _resample_data(
|
308
|
-
self, df: pd.DataFrame, interval: str, multiplier: int
|
309
|
-
) -> pd.DataFrame:
|
310
|
-
if interval == "day":
|
311
|
-
freq = f"{multiplier}D"
|
312
|
-
elif interval == "week":
|
313
|
-
freq = f"{multiplier}W-MON"
|
314
|
-
elif interval == "month":
|
315
|
-
freq = f"{multiplier}MS"
|
316
|
-
elif interval == "year":
|
317
|
-
freq = f"{multiplier}AS-JAN"
|
318
|
-
|
319
|
-
df["date"] = pd.to_datetime(df["date"])
|
320
|
-
df = df.set_index("date")
|
321
|
-
resampled = df.resample(freq).agg(
|
322
|
-
{
|
323
|
-
"open": "first",
|
324
|
-
"high": "max",
|
325
|
-
"low": "min",
|
326
|
-
"close": "last",
|
327
|
-
"volume": "sum",
|
328
|
-
}
|
329
|
-
)
|
330
|
-
return resampled.reset_index()
|
331
|
-
|
332
|
-
def _clean_hist_data(self, raw_df: pd.DataFrame, adjust: str) -> pd.DataFrame:
|
333
|
-
"""清理和标准化历史行情数据
|
334
|
-
|
335
|
-
Args:
|
336
|
-
raw_df: 原始数据DataFrame
|
337
|
-
adjust: 复权类型
|
338
|
-
|
339
|
-
Returns:
|
340
|
-
标准化后的DataFrame
|
341
|
-
"""
|
342
|
-
column_mapping = {
|
343
|
-
"date": "timestamp",
|
344
|
-
"open": "open",
|
345
|
-
"high": "high",
|
346
|
-
"low": "low",
|
347
|
-
"close": "close",
|
348
|
-
"volume": "volume",
|
349
|
-
}
|
350
|
-
|
351
|
-
df = raw_df.rename(columns=column_mapping)
|
352
|
-
|
353
|
-
# Process timestamp
|
354
|
-
if "timestamp" in df.columns:
|
355
|
-
df["timestamp"] = (
|
356
|
-
pd.to_datetime(df["timestamp"])
|
357
|
-
.dt.tz_localize("Asia/Shanghai")
|
358
|
-
.dt.tz_convert("UTC")
|
359
|
-
)
|
360
|
-
|
361
|
-
# Process volume
|
362
|
-
if "volume" in df.columns:
|
363
|
-
df["volume"] = df["volume"].astype("int64")
|
364
|
-
|
365
|
-
# Select and order columns
|
366
|
-
standard_columns = [
|
367
|
-
"timestamp",
|
368
|
-
"open",
|
369
|
-
"high",
|
370
|
-
"low",
|
371
|
-
"close",
|
372
|
-
"volume",
|
373
|
-
]
|
374
|
-
|
375
|
-
return df[[col for col in standard_columns if col in df.columns]]
|
376
|
-
|
377
212
|
def _clean_income_data(self, raw_df: pd.DataFrame) -> pd.DataFrame:
|
378
213
|
"""清理和标准化利润表数据
|
379
214
|
|
@@ -0,0 +1,64 @@
|
|
1
|
+
from abc import ABC, abstractmethod
|
2
|
+
import pandas as pd
|
3
|
+
|
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
|
+
class HistoricalDataProvider(ABC):
|
31
|
+
def __init__(
|
32
|
+
self,
|
33
|
+
symbol: str,
|
34
|
+
interval: str = "day",
|
35
|
+
interval_multiplier: int = 1,
|
36
|
+
start_date: str = "1970-01-01",
|
37
|
+
end_date: str = "2030-12-31",
|
38
|
+
adjust: str = "none",
|
39
|
+
) -> None:
|
40
|
+
self.symbol = symbol
|
41
|
+
self.interval = interval
|
42
|
+
self.interval_multiplier = interval_multiplier
|
43
|
+
self.start_date = start_date
|
44
|
+
self.end_date = end_date
|
45
|
+
self.adjust = adjust
|
46
|
+
|
47
|
+
@classmethod
|
48
|
+
def get_supported_intervals(cls):
|
49
|
+
return ["minute", "hour", "day", "week", "month", "year"]
|
50
|
+
|
51
|
+
@abstractmethod
|
52
|
+
def get_hist_data(self) -> pd.DataFrame:
|
53
|
+
"""Fetches historical market data
|
54
|
+
|
55
|
+
Returns:
|
56
|
+
pd.DataFrame:
|
57
|
+
- timestamp (UTC)
|
58
|
+
- open
|
59
|
+
- high
|
60
|
+
- low
|
61
|
+
- close
|
62
|
+
- volume
|
63
|
+
"""
|
64
|
+
pass
|