Exemplo n.º 1
0
    def __init__(self, market_data_generator = None, md_request = None):
        if market_data_generator is None:
            if DataConstants().default_market_data_generator == "marketdatagenerator":
                from findatapy.market import MarketDataGenerator
                market_data_generator = MarketDataGenerator()
            elif DataConstants().default_market_data_generator == 'cachedmarketdatagenerator':
                # NOT CURRENTLY IMPLEMENTED FOR FUTURE USE
                from finaddpy.market import CachedMarketDataGenerator
                market_data_generator = CachedMarketDataGenerator()

        self.speed_cache = SpeedCache()
        self.market_data_generator = market_data_generator
        self.md_request = md_request
Exemplo n.º 2
0
    def generate_key(self):
        from findatapy.market.ioengine import SpeedCache

        # Don't include any "large" objects in the key
        return SpeedCache().generate_key(self, [
            '_market_data_generator', '_calculations', '_calendar', '_filter'
        ])
Exemplo n.º 3
0
    def generate_key(self):
        """Generate a key to describe this MarketDataRequest object, which can 
        be used in a cache, as a hash-style key

        Returns
        -------
        str
            Key to describe this MarketDataRequest

        """
        from findatapy.market.ioengine import SpeedCache

        if self.freq == "daily":
            ticker = None
        else:
            ticker = self.tickers[0]

        self.__category_key = self.create_category_key(md_request=self,
                                                       ticker=ticker)

        return SpeedCache().generate_key(self,
                                         ["logger",
                                          "_MarketDataRequest__abstract_curve",
                                          "_MarketDataRequest__cache_algo",
                                          "_MarketDataRequest__overrides"]) \
               + "_df"
Exemplo n.º 4
0
class Market(object):
    """Higher level class which fetches market data using underlying classes such as MarketDataGenerator.

    Also contains several other classes, which are for asset specific instances, for example for generating FX spot time series
    or FX volatility surfaces.
    """
    def __init__(self, market_data_generator=None, md_request=None):
        if market_data_generator is None:
            if constants.default_market_data_generator == "marketdatagenerator":
                from findatapy.market import MarketDataGenerator
                market_data_generator = MarketDataGenerator()
            elif constants.default_market_data_generator == 'cachedmarketdatagenerator':
                # NOT CURRENTLY IMPLEMENTED FOR FUTURE USE
                from finaddpy.market import CachedMarketDataGenerator
                market_data_generator = CachedMarketDataGenerator()

        self.speed_cache = SpeedCache()
        self._market_data_generator = market_data_generator
        self._filter = Filter()
        self.md_request = md_request

    def fetch_market(self, md_request=None):
        """Fetches market data for specific tickers

        The user does not need to know to the low level API for each data provider works. The MarketDataRequest
        needs to supply parameters that define each data request. It has details which include:
            ticker eg. EURUSD
            field eg. close
            category eg. fx
            data_source eg. bloomberg
            start_date eg. 01 Jan 2015
            finish_date eg. 01 Jan 2017

        It can also have many optional attributes, such as
            vendor_ticker eg. EURUSD Curncy
            vendor_field eg. PX_LAST

        Parameters
        ----------
        md_request : MarketDataRequest
            Describing what market data to fetch

        Returns
        -------
        pd.DataFrame
            Contains the requested market data

        """
        if self.md_request is not None:
            md_request = self.md_request

        key = md_request.generate_key()

        data_frame = None

        # If internet_load has been specified don't bother going to cache (might end up calling lower level cache though
        # through MarketDataGenerator)
        if 'cache_algo' in md_request.cache_algo:
            data_frame = self.speed_cache.get_dataframe(key)

        if data_frame is not None:
            return data_frame

        # Special cases when a predefined category has been asked
        if md_request.category is not None:

            if (md_request.category == 'fx-spot-volume'
                    and md_request.data_source == 'quandl'):
                # NOT CURRENTLY IMPLEMENTED FOR FUTURE USE
                from findatapy.market.fxclsvolume import FXCLSVolume
                fxcls = FXCLSVolume(
                    market_data_generator=self._market_data_generator)

                data_frame = fxcls.get_fx_volume(
                    md_request.start_date,
                    md_request.finish_date,
                    md_request.tickers,
                    cut="LOC",
                    data_source="quandl",
                    cache_algo=md_request.cache_algo)

            # For FX we have special methods for returning cross rates or total returns
            if (md_request.category in ['fx', 'fx-tot', 'fx-tot-forwards']) and md_request.tickers is not None and \
                    md_request.abstract_curve is None:
                fxcf = FXCrossFactory(
                    market_data_generator=self._market_data_generator)

                if md_request.category == 'fx':
                    type = 'spot'
                elif md_request.category == 'fx-tot':
                    type = 'tot'

                elif md_request.category == 'fx-tot-forwards':
                    type = 'tot-forwards'

                if (md_request.freq != 'tick' and md_request.fields == ['close']) or \
                        (md_request.freq == 'tick' and md_request.data_source in ['dukascopy', 'fxcm']):
                    data_frame = fxcf.get_fx_cross(
                        md_request.start_date,
                        md_request.finish_date,
                        md_request.tickers,
                        cut=md_request.cut,
                        data_source=md_request.data_source,
                        freq=md_request.freq,
                        cache_algo=md_request.cache_algo,
                        type=type,
                        environment=md_request.environment,
                        fields=md_request.fields)

            # For FX implied volatility we can return the full surface
            if (md_request.category == 'fx-implied-vol'):
                if md_request.tickers is not None and md_request.freq == 'daily':
                    df = []

                    fxvf = FXVolFactory(
                        market_data_generator=self._market_data_generator)

                    for t in md_request.tickers:
                        if len(t) == 6:
                            df.append(
                                fxvf.get_fx_implied_vol(
                                    md_request.start_date,
                                    md_request.finish_date,
                                    t,
                                    md_request.fx_vol_tenor,
                                    cut=md_request.cut,
                                    data_source=md_request.data_source,
                                    part=md_request.fx_vol_part,
                                    cache_algo=md_request.cache_algo))

                    if df != []:
                        data_frame = Calculations().pandas_outer_join(df)

            # For FX vol market return all the market data necessary for pricing options
            # which includes FX spot, volatility surface, forward points, deposit rates
            if (md_request.category == 'fx-vol-market'):
                if md_request.tickers is not None:
                    df = []

                    fxcf = FXCrossFactory(
                        market_data_generator=self._market_data_generator)
                    fxvf = FXVolFactory(
                        market_data_generator=self._market_data_generator)
                    rates = RatesFactory(
                        market_data_generator=self._market_data_generator)

                    # For each FX cross fetch the spot, vol and forward points
                    for t in md_request.tickers:
                        if len(t) == 6:
                            # Spot
                            df.append(
                                fxcf.get_fx_cross(
                                    start=md_request.start_date,
                                    end=md_request.finish_date,
                                    cross=t,
                                    cut=md_request.cut,
                                    data_source=md_request.data_source,
                                    freq=md_request.freq,
                                    cache_algo=md_request.cache_algo,
                                    type='spot',
                                    environment=md_request.environment,
                                    fields=['close']))

                            # Entire FX vol surface
                            df.append(
                                fxvf.get_fx_implied_vol(
                                    md_request.start_date,
                                    md_request.finish_date,
                                    t,
                                    md_request.fx_vol_tenor,
                                    cut=md_request.cut,
                                    data_source=md_request.data_source,
                                    part=md_request.fx_vol_part,
                                    cache_algo=md_request.cache_algo))

                            # FX forward points for every point on curve
                            df.append(
                                rates.get_fx_forward_points(
                                    md_request.start_date,
                                    md_request.finish_date,
                                    t,
                                    md_request.fx_forwards_tenor,
                                    cut=md_request.cut,
                                    data_source=md_request.data_source,
                                    cache_algo=md_request.cache_algo))

                    # Lastly fetch the base depos
                    df.append(
                        rates.get_base_depos(
                            md_request.start_date,
                            md_request.finish_date,
                            self._get_base_depo_currencies(md_request.tickers),
                            md_request.base_depos_tenor,
                            cut=md_request.cut,
                            data_source=md_request.data_source,
                            cache_algo=md_request.cache_algo))

                    if df != []:
                        data_frame = Calculations().pandas_outer_join(df)

            if (md_request.category == 'fx-forwards-market'):
                if md_request.tickers is not None:
                    df = []

                    fxcf = FXCrossFactory(
                        market_data_generator=self._market_data_generator)
                    rates = RatesFactory(
                        market_data_generator=self._market_data_generator)

                    # For each FX cross fetch the spot and forward points
                    for t in md_request.tickers:
                        if len(t) == 6:
                            # Spot
                            df.append(
                                fxcf.get_fx_cross(
                                    start=md_request.start_date,
                                    end=md_request.finish_date,
                                    cross=t,
                                    cut=md_request.cut,
                                    data_source=md_request.data_source,
                                    freq=md_request.freq,
                                    cache_algo=md_request.cache_algo,
                                    type='spot',
                                    environment=md_request.environment,
                                    fields=['close']))

                            # FX forward points for every point on curve
                            df.append(
                                rates.get_fx_forward_points(
                                    md_request.start_date,
                                    md_request.finish_date,
                                    t,
                                    md_request.fx_forwards_tenor,
                                    cut=md_request.cut,
                                    data_source=md_request.data_source,
                                    cache_algo=md_request.cache_algo))

                    # Lastly fetch the base depos
                    df.append(
                        rates.get_base_depos(
                            md_request.start_date,
                            md_request.finish_date,
                            self._get_base_depo_currencies(md_request.tickers),
                            md_request.base_depos_tenor,
                            cut=md_request.cut,
                            data_source=md_request.data_source,
                            cache_algo=md_request.cache_algo))

                    if df != []:
                        data_frame = Calculations().pandas_outer_join(df)

            # eg. for calculating total return indices from first principles (rather than downloading them
            # from a data vendor
            if md_request.abstract_curve is not None:
                data_frame = md_request.abstract_curve.fetch_continuous_time_series \
                    (md_request, self._market_data_generator)

            if (md_request.category == 'crypto'):
                # Add more features later
                data_frame = self._market_data_generator.fetch_market_data(
                    md_request)

            # TODO add more special examples here for different asset classes
            # the idea is that we do all the market data downloading here, rather than elsewhere

        # By default: pass the market data request to MarketDataGenerator
        if data_frame is None:
            data_frame = self._market_data_generator.fetch_market_data(
                md_request)

        # Special case where we can sometimes have duplicated data times
        if md_request.freq == 'intraday' and md_request.cut == 'BSTP':
            data_frame = self._filter.remove_duplicate_indices(data_frame)

        # Push into cache
        if md_request.push_to_cache:
            self.speed_cache.put_dataframe(key, data_frame)

        return data_frame

    def _get_base_depo_currencies(self, cross):

        if not (isinstance(cross, list)):
            cross = [cross]

        base_depo_currencies = []

        for c in cross:
            base = c[0:3]
            terms = c[3:6]

            if base in constants.base_depos_currencies:
                base_depo_currencies.append(base)

            if terms in constants.base_depos_currencies:
                base_depo_currencies.append(terms)

        base_depo_currencies = list(set(base_depo_currencies))

        return base_depo_currencies