コード例 #1
0
def get_daily_interest_history(maturity: str,
                               start_date: Union[date, None] = None,
                               end_date: Union[date, None] = None) -> list:
    """
    Wrapper around external service request for US Treasury Yield Curve data. Relies on an instance of `StatManager` configured by `settings.STAT_MANAGER` value, which in turn is configured by the `STAT_MANAGER` environment variable, to hydrate with data.

    Before deferring to the `StatManager` and letting it call the external service, however, this function checks if response is in local cache. If the response is not in the cache, it will pass the request off to `StatManager` and then save the response in the cache so subsequent calls to the function can bypass the service request. Used to prevent excessive external HTTP requests and improve the performance of the application. Other parts of the program should interface with the external statistics data services through this function to utilize the cache functionality. 

    Parameters
    ----------
    1. **maturity** : ``str``
        Maturity of the US Treasury for which the interest rate will be retrieved. List of allowable values can in `scrilla.stats.keys['SERVICES']['STATISTICS']['QUANDL']['MAP']['YIELD_CURVE']`
    2. **start_date** : ``datetime.date``
        *Optional*. Start date of price history. Defaults to None. If `start_date is None`, the calculation is made as if the `start_date` were set to 100 trading days ago. This excludes weekends and holidays.
    3. **end_date** : ``datetime.date``
        *Optional*. End date of price history. Defaults to None. If `end_date is None`, the calculation is made as if the `end_date` were set to today. This excludes weekends and holidays so that `end_date` is set to the last previous business date.

    Returns
    ------
    ``dict`` : `{ 'date' :  value ,  'date':  value , ... }`
        Dictionary with date strings formatted `YYYY-MM-DD` as keys and the interest on that date as the corresponding value.

    .. notes::
        * Yield rates are not reported on weekends or holidays, so the `asset_type` for interest is functionally equivalent to equities, at least as far as date calculations are concerned. The dates inputted into this function are validated as if they were labelled as equity `asset_types` for this reason.
    """
    start_date, end_date = errors.validate_dates(
        start_date=start_date,
        end_date=end_date,
        asset_type=keys.keys['ASSETS']['EQUITY'])

    rates = None
    rates = interest_cache.filter_interest_cache(maturity,
                                                 start_date=start_date,
                                                 end_date=end_date)

    if rates is not None:
        logger.debug(
            f'Comparing {len(rates)} = {dater.business_days_between(start_date, end_date)}'
        )

    # TODO: this only works when stats are reported daily and that the latest date in the dataset is actually end_date.
    if rates is not None and \
            dater.to_string(end_date) in rates.keys() and \
            dater.business_days_between(start_date, end_date) == len(rates):
        return rates

    logger.debug(
        f'Cached {maturity} data is out of date, passing request to external service'
    )
    rates = stat_manager.get_interest_rates(start_date=start_date,
                                            end_date=end_date)

    for this_date in rates:
        interest_cache.save_row(date=this_date, value=rates[this_date])

    rates = stat_manager.format_for_maturity(maturity=maturity, results=rates)

    return rates
コード例 #2
0
def test_moving_average_return(ticker, start_date, end_date):
    with HTTMock(mock.mock_prices):
        moving_average = statistics.calculate_moving_averages(ticker=ticker, start_date=start_date, end_date=end_date)
    
    if get_asset_type(ticker) == keys['ASSETS']['CRYPTO']:
        no_of_days = dater.days_between(start_date, end_date)
    else:
        no_of_days = dater.business_days_between(start_date, end_date)

    assert isinstance(moving_average, dict)
    assert len(list(moving_average.keys())) == no_of_days
    assert all(isinstance(averages,dict) for averages in moving_average.values())
    assert all(all(isinstance(average,float) for average in average_dict.values()) for average_dict in moving_average.values())
コード例 #3
0
def test_standardized_sample_of_returns(ticker, start_date, end_date):
    with HTTMock(mock.mock_prices):
        these_returns = standardize(statistics.get_sample_of_returns(ticker=ticker,
                                                                        start_date=dater.parse(start_date),
                                                                        end_date=dater.parse(end_date)))
    
    if get_asset_type(ticker) == keys['ASSETS']['CRYPTO']:
        no_of_days = dater.days_between(start_date, end_date)
    else:
        no_of_days = dater.business_days_between(start_date, end_date)

    assert isinstance(these_returns, list)
    assert all(isinstance(this_return, float) for this_return in these_returns)
    # subtract one because differencing price history loses one sample
    assert len(these_returns) == no_of_days - 1
コード例 #4
0
def get_daily_price_history(
        ticker: str,
        start_date: Union[None, date] = None,
        end_date: Union[None, date] = None,
        asset_type: Union[None, str] = None) -> Dict[str, Dict[str, float]]:
    """
    Wrapper around external service request for price data. Relies on an instance of `PriceManager` configured by `settings.PRICE_MANAGER` value, which in turn is configured by the `PRICE_MANAGER` environment variable, to hydrate with data. 

    Before deferring to the `PriceManager` and letting it call the external service, however, this function checks if response is in local cache. If the response is not in the cache, it will pass the request off to `PriceManager` and then save the response in the cache so subsequent calls to the function can bypass the service request. Used to prevent excessive external HTTP requests and improve the performance of the application. Other parts of the program should interface with the external price data services through this function to utilize the cache functionality.

    Parameters
    ----------
    1. **ticker** :  ``str``
        Ticker symbol corresponding to the price history to be retrieved.
    2. **start_date** : ``datetime.date`` 
        *Optional*. Start date of price history. Defaults to None. If `start_date is None`, the calculation is made as if the `start_date` were set to 100 trading days ago. If `scrilla.files.get_asset_type(ticker)==scrill.keys.keys['ASSETS']['CRYPTO']`, this includes weekends and holidays. If `scrilla.files.get_asset_type(ticker)==scrilla.keys.keys['ASSETS']['EQUITY']`, this excludes weekends and holidays.
    3. **end_date** : ``datetime.date``
        Optional End date of price history. Defaults to None. If `end_date is None`, the calculation is made as if the `end_date` were set to today. If `scrilla.files.get_asset_type(ticker)==scrill.keys.keys['ASSETS']['CRYPTO']`, this means today regardless. If `scrilla.files.get_asset_type(ticker)==scrilla.keys.keys['ASSETS']['EQUITY']`, this excludes weekends and holidays so that `end_date` is set to the previous business date. 
    4. **asset_type** : ``string``
        *Optional*. Asset type of the ticker whose history is to be retrieved. Used to prevent excessive calls to IO and list searching. `asset_type` is determined by comparing the ticker symbol `ticker` to a large static list of ticker symbols maintained in installation directory's /data/static/ subdirectory, which can slow the program down if the file is constantly accessed and lots of comparison are made against it. Once an `asset_type` is calculated, it is best to preserve it in the process environment somehow, so this function allows the value to be passed in. If no value is detected, it will make a call to the aforementioned directory and parse the file to determine to the `asset_type`. Asset types are statically accessible through the `scrilla.keys.keys['ASSETS']` dictionary.

    Returns
    ------
    ``Dict[str, Dict[str, float]]`` : Dictionary with date strings formatted `YYYY-MM-DD` as keys and a nested dictionary containing the 'open' and 'close' price as values. Ordered from latest to earliest, e.g., 
    ```
        { 
            'date' : 
                { 
                    'open': value, 
                    'close': value  
                }, 
            'date': 
                { 
                    'open' : value, 
                    'close' : value 
                }, 
            ... 
        }
    ```

    Raises
    ------
    1. **scrilla.errors.PriceError**
        If no sample prices can be retrieved, this error is thrown. 

    .. notes::
        * The default analysis period, if no `start_date` and `end_date` are specified, is determined by the *DEFAULT_ANALYSIS_PERIOD** variable in the `settings,py` file. The default value of this variable is 100.
    """
    asset_type = errors.validate_asset_type(ticker, asset_type)
    start_date, end_date = errors.validate_dates(start_date, end_date,
                                                 asset_type)

    cached_prices = price_cache.filter_price_cache(ticker=ticker,
                                                   start_date=start_date,
                                                   end_date=end_date)

    if cached_prices is not None:
        if asset_type == keys.keys['ASSETS']['EQUITY']:
            logger.debug(
                f'Comparing {len(cached_prices)} = {dater.business_days_between(start_date, end_date)}'
            )
        elif asset_type == keys.keys['ASSETS']['CRYPTO']:
            logger.debug(
                f'Comparing {len(cached_prices)} = {dater.days_between(start_date, end_date)}'
            )

    # make sure the length of cache is equal to the length of the requested sample
    if cached_prices is not None and dater.to_string(
            end_date) in cached_prices.keys() and (
                (asset_type == keys.keys['ASSETS']['EQUITY'] and
                 (dater.business_days_between(
                     start_date, end_date)) == len(cached_prices)) or
                (asset_type == keys.keys['ASSETS']['CRYPTO'] and
                 (dater.days_between(start_date,
                                     end_date)) == len(cached_prices))):
        # TODO: debug the crypto out of date check.
        return cached_prices

    if cached_prices is not None:
        logger.debug(
            f'Cached {ticker} prices are out of date, passing request off to external service'
        )

    prices = price_manager.get_prices(ticker=ticker,
                                      start_date=start_date,
                                      end_date=end_date,
                                      asset_type=asset_type)

    if cached_prices is not None:
        new_prices = helper.complement_dict_keys(prices, cached_prices)
    else:
        new_prices = prices

    for this_date in new_prices:
        open_price = new_prices[this_date][keys.keys['PRICES']['OPEN']]
        close_price = new_prices[this_date][keys.keys['PRICES']['CLOSE']]
        price_cache.save_row(ticker=ticker,
                             date=this_date,
                             open_price=open_price,
                             close_price=close_price)

    if not prices:
        raise errors.PriceError(f'Prices could not be retrieved for {ticker}')

    return prices