跳轉到

finlab.data

finlab.data.get

get(dataset, save_to_storage=True, force_download=False)

下載歷史資料

請至歷史資料目錄 來獲得所有歷史資料的名稱,即可使用此函式來獲取歷史資料。 假設 save_to_storageTrue 則,程式會自動在本地複製一份,以避免重複下載大量數據。

PARAMETER DESCRIPTION
dataset

The name of dataset.

TYPE: str

save_to_storage

Whether to save the dataset to storage for later use. Default is True. The argument will be removed in the future. Please use data.set_storage(FileStorage(use_cache=True)) instead.

TYPE: bool DEFAULT: True

force_download

Whether to force download the dataset from cloud. Default is False.

TYPE: bool DEFAULT: False

RETURNS DESCRIPTION
DataFrame

financial data

Examples:

欲下載所有上市上櫃之收盤價歷史資料,只需要使用此函式即可:

from finlab import data
close = data.get('price:收盤價')
close
date 0015 0050 0051 0052 0053
2007-04-23 9.54 57.85 32.83 38.4 nan
2007-04-24 9.54 58.1 32.99 38.65 nan
2007-04-25 9.52 57.6 32.8 38.59 nan
2007-04-26 9.59 57.7 32.8 38.6 nan
2007-04-27 9.55 57.5 32.72 38.4 nan
Source code in finlab/data.py
def get(dataset: str, save_to_storage: bool = True, force_download=False):
    """下載歷史資料

    請至[歷史資料目錄](https://ai.finlab.tw/database) 來獲得所有歷史資料的名稱,即可使用此函式來獲取歷史資料。
    假設 `save_to_storage` 為 `True` 則,程式會自動在本地複製一份,以避免重複下載大量數據。

    Args:
        dataset (str): The name of dataset.
        save_to_storage (bool): Whether to save the dataset to storage for later use. Default is True. The argument will be removed in the future. Please use data.set_storage(FileStorage(use_cache=True)) instead.
        force_download (bool): Whether to force download the dataset from cloud. Default is False.

    Returns:
        (pd.DataFrame): financial data

    Examples:
        欲下載所有上市上櫃之收盤價歷史資料,只需要使用此函式即可:

        ``` py
        from finlab import data
        close = data.get('price:收盤價')
        close
        ```

        | date       |   0015 |   0050 |   0051 |   0052 |   0053 |
        |:-----------|-------:|-------:|-------:|-------:|-------:|
        | 2007-04-23 |   9.54 |  57.85 |  32.83 |  38.4  |    nan |
        | 2007-04-24 |   9.54 |  58.1  |  32.99 |  38.65 |    nan |
        | 2007-04-25 |   9.52 |  57.6  |  32.8  |  38.59 |    nan |
        | 2007-04-26 |   9.59 |  57.7  |  32.8  |  38.6  |    nan |
        | 2007-04-27 |   9.55 |  57.5  |  32.72 |  38.4  |    nan |

    """
    finlab.utils.check_version()

    global universe_stocks
    global _storage

    # not expired
    time_expired = _storage.get_time_expired(dataset)
    df = _storage.get_dataframe(dataset)
    if time_expired and time_expired > CacheStorage.now() and not force_download and df is not None and len(df) != 0:
        logger.debug(f'{dataset} not expired -> get data from local')
        return refine_stock_id(dataset, finlab.dataframe.FinlabDataFrame(df))

    # free user can only use historical data without merge
    global role
    if role == 'free' and df is not None:
        return refine_stock_id(dataset, finlab.dataframe.FinlabDataFrame(df))

    ############################
    # try to merge short data
    ############################
    url_data = fetch_data(dataset + '.recent', time_saved=_storage.get_time_created(dataset))
    if url_data is not None and df is not None and len(df) != 0 and not force_download:
        if 'data' not in url_data:
            _storage.set_time_expired(dataset, url_data['expiry'])
            logger.debug(f'{dataset} get recent, server says not expired -> get data from local')
            return refine_stock_id(dataset, finlab.dataframe.FinlabDataFrame(df))

        short_df = url_data['data']
        merge_success = False
        try:
            compare_cols = df.columns.intersection(['stock_id', 'date', '持股分級', 'broker'])
            df = pd.concat([df, short_df])\
                .pipe(lambda df: df[~df.duplicated(subset=compare_cols, keep='last')])\
                [short_df.columns]\
                .reset_index(drop=True)
            merge_success = True
        except Exception as e:
            # logger.warning(f'{dataset} get recent, merge fail -> cancel merge recent to local data')
            pass

        if merge_success:
            hash_df = hash(df)
            logger.debug(f'hash df: {hash_df} url: {url_data.get("hash", None)}')

            if url_data.get('hash', None) == hash_df and len(df) != 0:
                _storage.set_dataframe(dataset, df, expiry=url_data['expiry'])
                logger.debug('get recent, is valid -> and merge recent to local data')
                return refine_stock_id(dataset, finlab.dataframe.FinlabDataFrame(df))
            else:
                pass
                # logger.warning(f' {dataset} get recent, shape not valid -> cancel merge recent to local data')

    ###################
    # all data download
    ###################
    del df
    del url_data
    gc.collect()

    # expired at local but may not expired at server
    url_data = fetch_data(dataset)

    if url_data is None:
        raise Exception(f"**Error: {dataset} not exists")

    df = url_data['data']

    # fallback to cache storage if user is free user
    if url_data is not None and role is None:
        if url_data['role'] == 'free':
            role = 'free'
            _storage = CacheStorage()

    if len(df) > 0:
        _storage.set_dataframe(dataset, df, expiry=url_data['expiry'])

    if len(df) == 0:
        raise Exception(f"**Error: {dataset} download fail")

    logger.debug(f' {dataset} get recent, merge fail -> get whole data from cloud')
    return refine_stock_id(dataset, finlab.dataframe.FinlabDataFrame(df))

finlab.data.indicator

indicator(indname, adjust_price=False, resample='D', market='TW_STOCK', **kwargs)

支援 Talib 和 pandas_ta 上百種技術指標,計算 2000 檔股票、10年的所有資訊。

在使用這個函式前,需要安裝計算技術指標的 Packages

PARAMETER DESCRIPTION
indname

指標名稱, 以 TA-Lib 舉例,例如 SMA, STOCH, RSI 等,可以參考 talib 文件

以 Pandas-ta 舉例,例如 supertrend, ssf 等,可以參考 Pandas-ta 文件

TYPE: str

adjust_price

是否使用還原股價計算。

TYPE: bool DEFAULT: False

resample

技術指標價格週期,ex: D 代表日線, W 代表週線, M 代表月線。

TYPE: str DEFAULT: 'D'

market

市場選擇,ex: TW_STOCK 代表台股, US_STOCK 代表美股。

TYPE: str DEFAULT: 'TW_STOCK'

**kwargs

技術指標的參數設定,TA-Lib 中的 RSI 為例,調整項為計算週期 timeperiod=14

TYPE: dict DEFAULT: {}

建議使用者可以先參考以下範例,並且搭配 talib官方文件,就可以掌握製作技術指標的方法了。

Source code in finlab/data.py
def indicator(indname, adjust_price=False, resample='D', market='TW_STOCK', **kwargs):
    """支援 Talib 和 pandas_ta 上百種技術指標,計算 2000 檔股票、10年的所有資訊。

    在使用這個函式前,需要安裝計算技術指標的 Packages

    * [Ta-Lib](https://github.com/mrjbq7/ta-lib)
    * [Pandas-ta](https://github.com/twopirllc/pandas-ta)

    Args:
        indname (str): 指標名稱,
            以 TA-Lib 舉例,例如 SMA, STOCH, RSI 等,可以參考 [talib 文件](https://mrjbq7.github.io/ta-lib/doc_index.html)。

            以 Pandas-ta 舉例,例如 supertrend, ssf 等,可以參考 [Pandas-ta 文件](https://twopirllc.github.io/pandas-ta/#indicators-by-category)。
        adjust_price (bool): 是否使用還原股價計算。
        resample (str): 技術指標價格週期,ex: `D` 代表日線, `W` 代表週線, `M` 代表月線。
        market (str): 市場選擇,ex: `TW_STOCK` 代表台股, `US_STOCK` 代表美股。
        **kwargs (dict): 技術指標的參數設定,TA-Lib 中的 RSI 為例,調整項為計算週期 `timeperiod=14`。
    建議使用者可以先參考以下範例,並且搭配 talib官方文件,就可以掌握製作技術指標的方法了。
    """
    package = None

    try:
        from talib import abstract
        import talib
        attr = getattr(abstract, indname)
        package = 'talib'
    except:
        try:
            import pandas_ta
            # test df.ta has attribute
            getattr(pd.DataFrame().ta, indname)
            attr = lambda df, **kwargs: getattr(df.ta, indname)(**kwargs)
            package = 'pandas_ta'
        except:
            raise Exception(
                "Please install TA-Lib or pandas_ta to get indicators.")


    market = finlab.market_info.get_market_info(user_market_info=market)

    close = market.get_price('close', adj=adjust_price)
    open_ = market.get_price('open', adj=adjust_price)
    high = market.get_price('high', adj=adjust_price)
    low = market.get_price('low', adj=adjust_price)
    volume = market.get_price('volume', adj=adjust_price)

    if resample.upper() != 'D':
        close = close.resample(resample).last()
        open_ = open_.resample(resample).first()
        high = high.resample(resample).max()
        low = low.resample(resample).min()
        volume = volume.resample(resample).sum()

    latest_date = min([close.index[-1], open_.index[-1], high.index[-1], low.index[-1], volume.index[-1]])

    if (latest_date != close.index[-1] 
        or latest_date != open_.index[-1] 
        or latest_date != high.index[-1] 
        or latest_date != low.index[-1] 
        or latest_date != volume.index[-1]):

        logger.warning(f'indicator: {indname} market: {market} has different end date, '
                       'cut to {latest_date}. This is due to server updating data. '
                       'If you want to get the latest data, please try again 3 minutes later.')

        close = close.loc[:latest_date]
        open_ = open_.loc[:latest_date]
        high = high.loc[:latest_date]
        low = low.loc[:latest_date]
        volume = volume.loc[:latest_date]

    dfs = {}
    default_output_columns = None
    for key in close.columns:

        prices = {'open': open_[key].ffill(),
                  'high': high[key].ffill(),
                  'low': low[key].ffill(),
                  'close': close[key].ffill(),
                  'volume': volume[key].ffill()}

        if package == 'pandas_ta':
            prices = pd.DataFrame(prices)
            s = attr(prices, **kwargs)

        elif package == 'talib':
            abstract_input = list(attr.input_names.values())[0]
            abstract_input = get_input_args(attr)

            # quick fix talib bug
            if indname == 'OBV':
                abstract_input = ['close', 'volume']

            if indname == 'BETA':
                abstract_input = ['high', 'low']

            if isinstance(abstract_input, str):
                abstract_input = [abstract_input]
            paras = [prices[k] for k in abstract_input]
            s = attr(*paras, **kwargs)
        else:
            raise Exception("Cannot determine technical package from indname")

        if isinstance(s, list):
            s = {i: series for i, series in enumerate(s)}

        if isinstance(s, np.ndarray):
            s = {0: s}

        if isinstance(s, pd.Series):
            s = {0: s.values}

        if isinstance(s, pd.DataFrame):
            s = {i: series.values for i, series in s.items()}

        if default_output_columns is None:
            default_output_columns = list(s.keys())

        for colname, series in s.items():
            if colname not in dfs:
                dfs[colname] = {}
            dfs[colname][key] = series if isinstance(
                series, pd.Series) else series

    newdic = {}
    for key, df in dfs.items():
        newdic[key] = pd.DataFrame(df, index=close.index)

    ret = [newdic[n] for n in default_output_columns]
    ret = [d.apply(lambda s:pd.to_numeric(s, errors='coerce')) for d in ret]

    if len(ret) == 1:
        return finlab.dataframe.FinlabDataFrame(ret[0])

    return tuple([finlab.dataframe.FinlabDataFrame(df) for df in ret])

finlab.data.universe

universe(market='ALL', category='ALL')

當呼叫 data.get 或是 data.indicator 時,返回產業相關類股。

PARAMETER DESCRIPTION
market

Universe market type. ex: ALL, TSE, OTC, TSE_OTC, ETF, STOCK_FUTURE

TYPE: str DEFAULT: 'ALL'

category

Stock categories. ex: 光電業, 其他, 其他電子業, 化學工業, 半導體, 塑膠工業, 存託憑證, 建材營造, 文化創意業, 橡膠工業, 水泥工業,汽車工業, 油電燃氣業, 玻璃陶瓷, 生技醫療, 生技醫療業, 紡織纖維, 航運業, 觀光事業, 貿易百貨, 資訊服務業, 農業科技, 通信網路業, 造紙工業, 金融, 鋼鐵工業, 電器電纜, 電子商務, 電子通路業, 電子零組件, 電機機械, 電腦及週邊, 食品工業

TYPE: str or list DEFAULT: 'ALL'

Examples:

想要當鋼鐵人、航海王,可以用以下方法將這些類股一次選出來

with universe('TSE_OTC', ['鋼鐵工業', '航運業']):
    close_subset = data.get('price:收盤價')
    print(close_subset)

date 2002 2006 .. 2008 2009
2007-04-23 39.65 38.3 .. 7.8 17.55
2007-04-24 39.85 38.85 .. 8.34 17.5
2007-04-25 39.25 38.1 .. 8.25 17.3
2007-04-26 39 37.85 .. 8.2 17.3
2007-04-27 38.2 37.2 .. 7.88 16.6
Source code in finlab/data.py
def __init__(self, market='ALL', category='ALL'):
    """當呼叫 `data.get` 或是 `data.indicator` 時,返回產業相關類股。

    Args:
        market (str): Universe market type. ex: `ALL`, `TSE`, `OTC`, `TSE_OTC`, `ETF`, `STOCK_FUTURE`
        category (str or list)): Stock categories. ex: `光電業`, `其他`, `其他電子業`, `化學工業`, `半導體`, `塑膠工業`, `存託憑證`, `建材營造`, `文化創意業`, `橡膠工業`, `水泥工業`,`汽車工業`, `油電燃氣業`, `玻璃陶瓷`, `生技醫療`, `生技醫療業`, `紡織纖維`, `航運業`, `觀光事業`, `貿易百貨`, `資訊服務業`, `農業科技`, `通信網路業`, `造紙工業`, `金融`, `鋼鐵工業`, `電器電纜`, `電子商務`, `電子通路業`, `電子零組件`, `電機機械`, `電腦及週邊`, `食品工業`

    Examples:
        想要當鋼鐵人、航海王,可以用以下方法將這些類股一次選出來
        ``` py
        with universe('TSE_OTC', ['鋼鐵工業', '航運業']):
            close_subset = data.get('price:收盤價')
            print(close_subset)
        ```

        | date       |   2002 |   2006 |   ..   |   2008 |   2009 |
        |:-----------|-------:|-------:|-------:|-------:|-------:|
        | 2007-04-23 |  39.65 |  38.3  |   ..   |   7.8  |  17.55 |
        | 2007-04-24 |  39.85 |  38.85 |   ..   |   8.34 |  17.5  |
        | 2007-04-25 |  39.25 |  38.1  |   ..   |   8.25 |  17.3  |
        | 2007-04-26 |  39    |  37.85 |   ..   |   8.2  |  17.3  |
        | 2007-04-27 |  38.2  |  37.2  |   ..   |   7.88 |  16.6  |

    """
    self._market = market
    self._category = category
    self._previous_stocks = set()

finlab.data.us_universe

us_universe(market='ALL', sector='ALL', industry='ALL', exchange='ALL')

當呼叫 data.get 或是 data.indicator 時,返回美股產業相關類股。

PARAMETER DESCRIPTION
market

Universe market type. ex: Common Stock, Preferred Stock, Domestic, Domestic Common Stock, ADR

TYPE: str DEFAULT: 'ALL'

sector

The sector the stock belongs to. ex:Basic Materials,Communication Services,Consumer Cyclical,Consumer Defensive,Energy,Financial Services,Healthcare,Industrials,Real Estate,Technology,Utilities

TYPE: str or list DEFAULT: 'ALL'

industry

The industry the stock belongs to.See industry list from set(data.get('us_tickers')['industry']).ex:Steel,Software - Application...

TYPE: str or list DEFAULT: 'ALL'

exchange

The exchange the stock belongs to. ex:BATS, INDEX, NASDAQ, NYSE, NYSEARCA, NYSEMKT, OTC

TYPE: str or list DEFAULT: 'ALL'

Examples:

想選出美股普通股中的科技類股

with us_universe('Common Stock', ['Technology']):
    close_subset = data.get('us_price:close')
    print(close_subset)

date AAOI AAPL .. ABCO NVDA
2017-01-03 39.65 38.3 .. 7.8 17.55
2017-01-04 39.85 38.85 .. 8.34 17.5
2017-01-05 39.25 38.1 .. 8.25 17.3
2017-01-06 39 37.85 .. 8.2 17.3
2017-01-09 38.2 37.2 .. 7.88 16.6

想選出美股特別股中的基礎原物料和能源類股

with data.us_universe('Preferred Stock', ['Basic Materials','Energy']):
    close_subset = data.get('us_price:close')
    print(close_subset)

date AEUA ALIN-PA .. ALIN-PB ALIN-PE
2017-01-03 39.65 38.3 .. 7.8 17.55
2017-01-04 39.85 38.85 .. 8.34 17.5
2017-01-05 39.25 38.1 .. 8.25 17.3
2017-01-06 39 37.85 .. 8.2 17.3
2017-01-09 38.2 37.2 .. 7.88 16.6

想從美股 NASDAQ 交易所的普通股中篩選出軟體類股

with data.us_universe('Common Stock', industry='Software', exchange='NASDAQ'):
    close_subset = data.get('us_price:close')
    print(close_subset)

date ACIW ACVA .. ZI ZS
2017-01-03 39.65 38.3 .. 7.8 17.55
2017-01-04 39.85 38.85 .. 8.34 17.5
2017-01-05 39.25 38.1 .. 8.25 17.3
2017-01-06 39 37.85 .. 8.2 17.3
2017-01-09 38.2 37.2 .. 7.88 16.6

檢視有哪些產業可選擇

print(set(data.get('us_tickers')['industry']))
{'Advertising Agencies',
 'Aerospace & Defense',
 'Agricultural Inputs',
 'Airlines',
 'Airports & Air Services',
 'Aluminum',
 ...}

Source code in finlab/data.py
def __init__(self, market='ALL', sector='ALL', industry='ALL', exchange='ALL'):
    """當呼叫 `data.get` 或是 `data.indicator` 時,返回美股產業相關類股。

    Args:
        market (str): Universe market type.
                      ex: `Common Stock`, `Preferred Stock`, `Domestic`, `Domestic Common Stock`, `ADR`
        sector (str or list): The sector the stock belongs to.
                              ex:`Basic Materials`,`Communication Services`,`Consumer Cyclical`,`Consumer Defensive`,`Energy`,`Financial Services`,`Healthcare`,`Industrials`,`Real Estate`,`Technology`,`Utilities`
        industry (str or list): The industry the stock belongs to.See industry list from `set(data.get('us_tickers')['industry'])`.ex:`Steel`,`Software - Application`...
        exchange (str or list): The exchange the stock belongs to.
                               ex:`BATS`, `INDEX`, `NASDAQ`, `NYSE`, `NYSEARCA`, `NYSEMKT`, `OTC`

    Examples:
        想選出美股普通股中的科技類股
        ``` py
        with us_universe('Common Stock', ['Technology']):
            close_subset = data.get('us_price:close')
            print(close_subset)
        ```

        | date       |   AAOI  |  AAPL |   ..   |   ABCO |   NVDA |
        |:-----------|-------:|-------:|-------:|-------:|-------:|
        | 2017-01-03 |  39.65 |  38.3  |   ..   |   7.8  |  17.55 |
        | 2017-01-04 |  39.85 |  38.85 |   ..   |   8.34 |  17.5  |
        | 2017-01-05 |  39.25 |  38.1  |   ..   |   8.25 |  17.3  |
        | 2017-01-06 |  39    |  37.85 |   ..   |   8.2  |  17.3  |
        | 2017-01-09 |  38.2  |  37.2  |   ..   |   7.88 |  16.6  |

        想選出美股特別股中的基礎原物料和能源類股
        ``` py
        with data.us_universe('Preferred Stock', ['Basic Materials','Energy']):
            close_subset = data.get('us_price:close')
            print(close_subset)
        ```

        | date       |   AEUA |  ALIN-PA |  ..  | ALIN-PB | ALIN-PE |
        |:-----------|-------:|-------:|-------:|-------:|-------:|
        | 2017-01-03 |  39.65 |  38.3  |   ..   |   7.8  |  17.55 |
        | 2017-01-04 |  39.85 |  38.85 |   ..   |   8.34 |  17.5  |
        | 2017-01-05 |  39.25 |  38.1  |   ..   |   8.25 |  17.3  |
        | 2017-01-06 |  39    |  37.85 |   ..   |   8.2  |  17.3  |
        | 2017-01-09 |  38.2  |  37.2  |   ..   |   7.88 |  16.6  |

        想從美股 NASDAQ 交易所的普通股中篩選出軟體類股
        ``` py
        with data.us_universe('Common Stock', industry='Software', exchange='NASDAQ'):
            close_subset = data.get('us_price:close')
            print(close_subset)
        ```

        | date       |   ACIW |  ACVA |  ..  | ZI | ZS |
        |:-----------|-------:|-------:|-------:|-------:|-------:|
        | 2017-01-03 |  39.65 |  38.3  |   ..   |   7.8  |  17.55 |
        | 2017-01-04 |  39.85 |  38.85 |   ..   |   8.34 |  17.5  |
        | 2017-01-05 |  39.25 |  38.1  |   ..   |   8.25 |  17.3  |
        | 2017-01-06 |  39    |  37.85 |   ..   |   8.2  |  17.3  |
        | 2017-01-09 |  38.2  |  37.2  |   ..   |   7.88 |  16.6  |


        檢視有哪些產業可選擇
        ``` py
        print(set(data.get('us_tickers')['industry']))
        ```
        ```
        {'Advertising Agencies',
         'Aerospace & Defense',
         'Agricultural Inputs',
         'Airlines',
         'Airports & Air Services',
         'Aluminum',
         ...}
        ```

    """
    self._market = market
    self._sector = sector
    self._industry = industry
    self._exchange = exchange
    self._previous_stocks = set()

finlab.data.set_storage

set_storage(storage)

設定本地端儲存歷史資料的方式 假設使用 data.get 獲取歷史資料則,在預設情況下,程式會自動在本地複製一份,以避免重複下載大量數據。 storage 就是用來儲存歷史資料的接口。我們提供兩種 storage 接口,分別是 finlab.data.CacheStorage (預設) 以及 finlab.data.FileStorage。前者是直接存在記憶體中,後者是存在檔案中。詳情請參考 CacheStorageFileStorage 來獲得更詳細的資訊。 在預設情況下,程式會自動使用 finlab.data.FileStorage 並將重複索取之歷史資料存在作業系統預設「暫時資料夾」。

PARAMETER DESCRIPTION
storage

The interface of storage

TYPE: Storage

Examples:

欲切換成以檔案方式儲存,可以用以下之方式:

from finlab import data
data.set_storage(data.FileStorage())
close = data.get('price:收盤價')

可以在本地端的 ./finlab_db/price#收盤價.pickle 中,看到下載的資料, 可以使用 pickle 調閱歷史資料:

import pickle
close = pickle.load(open('finlab_db/price#收盤價.pickle', 'rb'))

Source code in finlab/data.py
def set_storage(storage):
    """設定本地端儲存歷史資料的方式
    假設使用 `data.get` 獲取歷史資料則,在預設情況下,程式會自動在本地複製一份,以避免重複下載大量數據。
    storage 就是用來儲存歷史資料的接口。我們提供兩種 `storage` 接口,分別是 `finlab.data.CacheStorage` (預設) 以及
    `finlab.data.FileStorage`。前者是直接存在記憶體中,後者是存在檔案中。詳情請參考 `CacheStorage` 和 `FileStorage` 來獲得更詳細的資訊。
    在預設情況下,程式會自動使用 `finlab.data.FileStorage` 並將重複索取之歷史資料存在作業系統預設「暫時資料夾」。

    Args:
        storage (data.Storage): The interface of storage

    Examples:
        欲切換成以檔案方式儲存,可以用以下之方式:

        ``` py
        from finlab import data
        data.set_storage(data.FileStorage())
        close = data.get('price:收盤價')
        ```

        可以在本地端的 `./finlab_db/price#收盤價.pickle` 中,看到下載的資料,
        可以使用 `pickle` 調閱歷史資料:
        ``` py
        import pickle
        close = pickle.load(open('finlab_db/price#收盤價.pickle', 'rb'))
        ```
    """

    global _storage
    _storage = storage

finlab.data.CacheStorage

CacheStorage()

將歷史資料儲存於快取中

Examples:

欲切換成以檔案方式儲存,可以用以下之方式:

from finlab import data
data.set_storage(data.CacheStorage())
close = data.get('price:收盤價')

可以直接調閱快取資料:

close = data._storage._cache['price:收盤價']
Source code in finlab/data.py
def __init__(self):
    """將歷史資料儲存於快取中

      Examples:
          欲切換成以檔案方式儲存,可以用以下之方式:

          ``` py
          from finlab import data
          data.set_storage(data.CacheStorage())
          close = data.get('price:收盤價')
          ```

          可以直接調閱快取資料:

          ``` py
          close = data._storage._cache['price:收盤價']
          ```
    """

    self._cache = {}
    self._cache_time = {}
    self._cache_expiry = {}
    self._stock_names = {}

finlab.data.FileStorage

FileStorage(path=None, use_cache=True)

將歷史資料儲存於檔案中

PARAMETER DESCRIPTION
path

資料儲存的路徑

TYPE: str DEFAULT: None

use_cache

是否額外使用快取,將資料複製一份到記憶體中。

TYPE: bool DEFAULT: True

Examples:

欲切換成以檔案方式儲存,可以用以下之方式:

from finlab import data
data.set_storage(data.FileStorage())
close = data.get('price:收盤價')

可以在本地端的 ./finlab_db/price#收盤價.pickle 中,看到下載的資料, 可以使用 pickle 調閱歷史資料:

import pickle
close = pickle.load(open('finlab_db/price#收盤價.pickle', 'rb'))

Source code in finlab/data.py
def __init__(self, path=None, use_cache=True):
    """將歷史資料儲存於檔案中

      Args:
            path (str): 資料儲存的路徑
            use_cache (bool): 是否額外使用快取,將資料複製一份到記憶體中。

      Examples:
          欲切換成以檔案方式儲存,可以用以下之方式:

          ``` py
          from finlab import data
          data.set_storage(data.FileStorage())
          close = data.get('price:收盤價')
          ```

          可以在本地端的 `./finlab_db/price#收盤價.pickle` 中,看到下載的資料,
          可以使用 `pickle` 調閱歷史資料:
          ``` py
          import pickle
          close = pickle.load(open('finlab_db/price#收盤價.pickle', 'rb'))
          ```
    """
    if path is None:
        path = finlab.utils.get_tmp_dir()

    self._path = path
    self._cache = {}
    self._stock_names = None
    self._expiry = {}
    self.use_cache = use_cache

    if not os.path.isdir(path):
        os.mkdir(path)

    f_stock_names = os.path.join(path, 'stock_names.pkl')

    if not os.path.isfile(f_stock_names):
        with open(f_stock_names, 'wb') as f:
            pickle.dump({}, f)
    else:
        with open(f_stock_names, 'rb') as f:
            self._stock_names = pickle.load(f)

    f_expiry = os.path.join(self._path, 'expiry.pkl')

    if os.path.isfile(f_expiry):
        with open(f_expiry, 'rb') as f:
            try:
                self._expiry = pickle.load(f)
            except:
                self._expiry = {}

    if self._expiry:
        res = finlab.utils.requests.get('https://asia-east1-fdata-299302.cloudfunctions.net/data_reset_time')
        reset_data_time = datetime.datetime.fromtimestamp(float(res.text), tz=datetime.timezone.utc)
        for k, v in self._expiry.items():
            created = self.get_time_created(k)
            if created and created  < reset_data_time:
                logger.info(f' set {k} time expired since the system reset time: {reset_data_time} > created time: {self.get_time_created(k)}')
                self.set_time_expired(k, reset_data_time, save=False)

    self.save_expiry()

finlab.data.get_strategies

get_strategies(api_token=None)

取得已上傳量化平台的策略回傳資料。

可取得自己策略儀表板上的數據,例如每個策略的報酬率曲線、報酬率統計、夏普率、近期部位、近期換股日..., 這些數據可以用來進行多策略彙整的應用喔!

PARAMETER DESCRIPTION
api_token

若未帶入finlab模組的api_token,會自動跳出GUI頁面, 複製網頁內的api_token貼至輸入欄位即可。

TYPE: str DEFAULT: None

Returns: (dict): strategies data Response detail:

``` py
{
  strategy1:{
    'asset_type': '',
    'drawdown_details': {
       '2015-06-04': {
         'End': '2015-11-03',
         'Length': 152,
         'drawdown': -0.19879090089478024
         },
         ...
      },
    'fee_ratio': 0.000475,
    'last_trading_date': '2022-06-10',
    'last_updated': 'Sun, 03 Jul 2022 12:02:27 GMT',
    'ndays_return': {
      '1': -0.01132480035770611,
      '10': -0.0014737286933147464,
      '20': -0.06658015749110646,
      '5': -0.002292995729485159,
      '60': -0.010108700314771735
      },
    'next_trading_date': '2022-06-10',
    'positions': {
      '1413 宏洲': {
        'entry_date': '2022-05-10',
        'entry_price': 10.05,
        'exit_date': '',
        'next_weight': 0.1,
        'return': -0.010945273631840613,
        'status': '買進',
        'weight': 0.1479332345384493
        },
      'last_updated': 'Sun, 03 Jul 2022 12:02:27 GMT',
      'next_trading_date': '2022-06-10',
      'trade_at': 'open',
      'update_date': '2022-06-10'
      },
    'return_table': {
      '2014': {
        'Apr': 0.0,
        'Aug': 0.06315180932606546,
        'Dec': 0.0537589857541485,
        'Feb': 0.0,
        'Jan': 0.0,
        'Jul': 0.02937490104459939,
        'Jun': 0.01367930162104769,
        'Mar': 0.0,
        'May': 0.0,
        'Nov': -0.0014734320286596825,
        'Oct': -0.045082529665408266,
        'Sep': 0.04630906972509852,
        'YTD': 0.16626214846456966
        },
        ...
      },
    'returns': {
      'time': [
        '2014-06-10',
        '2014-06-11',
        '2014-06-12',
        ...
        ],
      'value': [
        100,
        99.9,
        100.2,
        ...
        ]
      },
    'stats': {
      'avg_down_month': -0.03304015302646822,
      'avg_drawdown': -0.0238021414698247,
      'avg_drawdown_days': 19.77952755905512,
      'avg_up_month': 0.05293384465715908,
      'cagr': 0.33236021285588846,
      'calmar': 1.65261094975066,
      'daily_kurt': 4.008888367138843,
      'daily_mean': 0.3090784769257415,
      'daily_sharpe': 1.747909002374217,
      'daily_skew': -0.6966018726321078,
      'daily_sortino': 2.8300677082214034,
      ...
      },
    'tax_ratio': 0.003,
    'trade_at': 'open',
    'update_date': '2022-06-10'
    },
  strategy2:{...},
  ...}
```
Source code in finlab/data.py
def get_strategies(api_token=None):
    """取得已上傳量化平台的策略回傳資料。

    可取得自己策略儀表板上的數據,例如每個策略的報酬率曲線、報酬率統計、夏普率、近期部位、近期換股日...,
    這些數據可以用來進行多策略彙整的應用喔!


    Args:
        api_token (str): 若未帶入finlab模組的api_token,會自動跳出[GUI](https://ai.finlab.tw/api_token/)頁面,
                         複製網頁內的api_token貼至輸入欄位即可。
    Returns:
        (dict): strategies data
    Response detail:

        ``` py
        {
          strategy1:{
            'asset_type': '',
            'drawdown_details': {
               '2015-06-04': {
                 'End': '2015-11-03',
                 'Length': 152,
                 'drawdown': -0.19879090089478024
                 },
                 ...
              },
            'fee_ratio': 0.000475,
            'last_trading_date': '2022-06-10',
            'last_updated': 'Sun, 03 Jul 2022 12:02:27 GMT',
            'ndays_return': {
              '1': -0.01132480035770611,
              '10': -0.0014737286933147464,
              '20': -0.06658015749110646,
              '5': -0.002292995729485159,
              '60': -0.010108700314771735
              },
            'next_trading_date': '2022-06-10',
            'positions': {
              '1413 宏洲': {
                'entry_date': '2022-05-10',
                'entry_price': 10.05,
                'exit_date': '',
                'next_weight': 0.1,
                'return': -0.010945273631840613,
                'status': '買進',
                'weight': 0.1479332345384493
                },
              'last_updated': 'Sun, 03 Jul 2022 12:02:27 GMT',
              'next_trading_date': '2022-06-10',
              'trade_at': 'open',
              'update_date': '2022-06-10'
              },
            'return_table': {
              '2014': {
                'Apr': 0.0,
                'Aug': 0.06315180932606546,
                'Dec': 0.0537589857541485,
                'Feb': 0.0,
                'Jan': 0.0,
                'Jul': 0.02937490104459939,
                'Jun': 0.01367930162104769,
                'Mar': 0.0,
                'May': 0.0,
                'Nov': -0.0014734320286596825,
                'Oct': -0.045082529665408266,
                'Sep': 0.04630906972509852,
                'YTD': 0.16626214846456966
                },
                ...
              },
            'returns': {
              'time': [
                '2014-06-10',
                '2014-06-11',
                '2014-06-12',
                ...
                ],
              'value': [
                100,
                99.9,
                100.2,
                ...
                ]
              },
            'stats': {
              'avg_down_month': -0.03304015302646822,
              'avg_drawdown': -0.0238021414698247,
              'avg_drawdown_days': 19.77952755905512,
              'avg_up_month': 0.05293384465715908,
              'cagr': 0.33236021285588846,
              'calmar': 1.65261094975066,
              'daily_kurt': 4.008888367138843,
              'daily_mean': 0.3090784769257415,
              'daily_sharpe': 1.747909002374217,
              'daily_skew': -0.6966018726321078,
              'daily_sortino': 2.8300677082214034,
              ...
              },
            'tax_ratio': 0.003,
            'trade_at': 'open',
            'update_date': '2022-06-10'
            },
          strategy2:{...},
          ...}
        ```
    """
    if api_token is None:
        api_token = finlab.get_token()

    request_args = {
        'api_token': api_token,
    }

    url = 'https://asia-east2-fdata-299302.cloudfunctions.net/auth_get_strategies'
    response = finlab.utils.requests.get(url, request_args)
    status_code = response.status_code
    if status_code in [400, 401]:
        logger.error("The authentication code is wrong or the account is not existed."
                     "Please input right authentication code or register account ")
        return {}
    try:
        return json.loads(response.text)
    except:
        pass

    return response.text

finlab.data.search

search(keyword=None, display_info=['name', 'description', 'items'])

查詢與取得資料庫目錄資訊。

查詢FinLab資料庫目錄中的資料表名稱或項目欄位名稱是否包含關鍵字,方便搜尋資料庫是否存在目標資料。

PARAMETER DESCRIPTION
keyword

欲查詢關鍵字。

TYPE: str DEFAULT: None

display_info

指定顯示的資訊項目,預設只顯示「資料表英文代稱、資料表的中文描述、資料表欄位名稱」,若設定為None,則顯示全部資訊。

TYPE: list DEFAULT: ['name', 'description', 'items']

RETURNS DESCRIPTION
list

database information

Response detail
[{'name': 'financial_statement',
  'description': '財報',
  'items': {'存貨': {'type': 'float', 'description': '資產負債表(仟元)'},
            '存貨_增加_減少': {'type': 'float', 'description': '單季現金流量表(仟元)'}}},
 {'name': 'fundamental_features',
  'description': '財務指標',
  'items': {'存貨週轉率': {'type': 'float', 'description': '(%)'}}},...]

Examples:

# 查詢各資料表的欄位名稱含有'存貨'關鍵字資料表的基本資訊
ex1 = data.search(keyword='存貨')
# 取得含有'存貨'關鍵字相關資料表的所有資訊
ex2 = data.search(keyword='存貨', display_info=None)

Source code in finlab/data.py
def search(keyword=None, display_info=['name', 'description', 'items']):
    """查詢與取得資料庫目錄資訊。

    查詢FinLab資料庫目錄中的資料表名稱或項目欄位名稱是否包含關鍵字,方便搜尋資料庫是否存在目標資料。

    Args:
        keyword (str): 欲查詢關鍵字。
        display_info (list):指定顯示的資訊項目,預設只顯示「資料表英文代稱、資料表的中文描述、資料表欄位名稱」,若設定為None,則顯示全部資訊。

    Returns:
        (list): database information

    Response detail:
        ``` py
        [{'name': 'financial_statement',
          'description': '財報',
          'items': {'存貨': {'type': 'float', 'description': '資產負債表(仟元)'},
                    '存貨_增加_減少': {'type': 'float', 'description': '單季現金流量表(仟元)'}}},
         {'name': 'fundamental_features',
          'description': '財務指標',
          'items': {'存貨週轉率': {'type': 'float', 'description': '(%)'}}},...]

        ```
    Examples:
        ``` py

        # 查詢各資料表的欄位名稱含有'存貨'關鍵字資料表的基本資訊
        ex1 = data.search(keyword='存貨')
        # 取得含有'存貨'關鍵字相關資料表的所有資訊
        ex2 = data.search(keyword='存貨', display_info=None)
        ```
    """
    if not hasattr(search, 'db_info'):
        res = finlab.utils.requests.get('https://asia-east2-fdata-299302.cloudfunctions.net/get_data_info')
        search.db_info = json.loads(res.text)['data']

    db_info = search.db_info

    if display_info:
        db_info = [{i: table[i] for i in display_info} for table in db_info]

    result = []
    if keyword:
        result = [table for table in db_info if (re.search(keyword, table['description'], re.IGNORECASE)) or (
            re.search(keyword, table['name'], re.IGNORECASE))]
        result_tables = [table['name'] for table in result]

    def check_column_contains_keyword(table, keyword):
        table = table.copy()
        keyword_exist = {k: v for k, v in table['items'].items() if re.search(keyword, k, re.IGNORECASE)}
        if len(keyword_exist) > 0:
            table['items'] = keyword_exist
            return table

    if keyword:
        for table in db_info:
            if table['name'] not in result_tables:
                checked_table = check_column_contains_keyword(table, keyword=keyword)
            if checked_table is not None:
                result.append(checked_table)
    return result