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 fetch_market(self, md_request=None): if self.md_request is not None: md_request = self.md_request # 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) return fxcls.get_fx_volume(md_request.start_date, md_request.finish_date, md_request.tickers, cut="LOC", source="quandl", cache_algo=md_request.cache_algo) if (md_request.category == 'fx' or md_request.category == 'fx-tot') and md_request.tickers is not 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' if (md_request.freq != 'tick' and md_request.fields == ['close']) or ( md_request.freq == 'tick' and md_request.data_source == 'dukascopy'): return fxcf.get_fx_cross( md_request.start_date, md_request.finish_date, md_request.tickers, cut=md_request.cut, source=md_request.data_source, freq=md_request.freq, cache_algo=md_request.cache_algo, type=type, environment=md_request.environment) 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, fxvf.tenor, cut=md_request.cut, source=md_request.data_source, part=fxvf.part, cache_algo_return=md_request.cache_algo)) if df != []: return Calculations().pandas_outer_join(df) 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 t in md_request.tickers: if len(t) == 6: df.append( fxcf.get_fx_cross( start=md_request.start_date, end=md_request.finish_date, cross=t, cut=md_request.cut, source=md_request.data_source, freq=md_request.freq, cache_algo=md_request.cache_algo, type='spot', environment=md_request.environment, fields=['close'])) df.append( fxvf.get_fx_implied_vol( md_request.start_date, md_request.finish_date, t, fxvf.tenor, cut=md_request.cut, source=md_request.data_source, part=fxvf.part, cache_algo=md_request.cache_algo)) df.append( rates.get_fx_forward_points( md_request.start_date, md_request.finish_date, t, fxvf.tenor, cut=md_request.cut, source=md_request.data_source, cache_algo=md_request.cache_algo)) df.append( rates.get_base_depos(md_request.start_date, md_request.finish_date, ["USD", "EUR", "CHF", "GBP"], fxvf.tenor, cut=md_request.cut, source=md_request.data_source, cache_algo=md_request.cache_algo)) if df != []: return Calculations().pandas_outer_join(df) # 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 return self.market_data_generator.fetch_market_data(md_request)