Пример #1
0
    def _build_metadata(self):
        bbg = BBG()
        country = bbg.fetch_contract_parameter(self.comm_bbg_code + '1 Comdty',
                                               'COUNTRY_ISO').iloc[0,
                                                                   0].upper()
        self.fh_ticker = 'comm ' + country.lower(
        ) + ' ' + self.comm_bbg_code.lower()
        currency = bbg.fetch_contract_parameter(
            self.comm_bbg_code + '1 Comdty', 'CRNCY').iloc[0, 0].upper()

        df = pd.DataFrame(data={
            'fh_ticker':
            self.fh_ticker,
            'asset_class':
            'commodity',
            'type':
            'future',
            'exchange_symbol':
            self.comm_bbg_code.upper(),
            'currency':
            currency,
            'country':
            country,
            'sector':
            self.sector_dict[self.comm_bbg_code.upper()],
            'roll_method':
            ' '.join(self.roll_schedule)
        },
                          index=[self.comm_bbg_code])

        return df
Пример #2
0
    def _grab_bbg_data(self):
        bbg = BBG()
        self.contract_list = bbg.fetch_futures_list(
            generic_ticker=self.comm_bbg_code + '1 Comdty')
        self.first_notice_dates = bbg.fetch_contract_parameter(
            securities=self.contract_list,
            field='FUT_NOTICE_FIRST').sort_values('FUT_NOTICE_FIRST')

        # Grab all contract series
        df_prices = bbg.fetch_series(securities=self.contract_list,
                                     fields='PX_LAST',
                                     startdate=self.start_date,
                                     enddate=self.end_date)
        self.prices = df_prices.fillna(method='ffill')
Пример #3
0
    def __init__(self, bbg_ticker, price_field='PX_LAST'):
        """
        Returns an object with the following attributes:
            - ticker: str with bloomberg ticker for the stock
            - dividends: DataFrame with dividend information. Its columns are 'Declared Date', 'Amount', 'Frequency',
                         'Type', 'Ex-Dividend Date', 'Payable Date', 'Record Date'
            - price: Series with the stock price
            - tr_index: Series with the total return index
            - quantity: amount of stocks held
            - ts_df: DataFrame with columns 'Price', 'Dividend', 'Quantity' and 'Total Return Index'
        :param bbg_ticker: str, Bloomberg ticker of the stock
        :param price_field: Price field to be used as settlement price
        """

        bbg = BBG()
        self.bbg_ticker = bbg_ticker

        today = pd.to_datetime('today')
        self.dividends = self._get_dividends(today, bbg)
        start_date_div = self.dividends['Ex-Dividend Date'].min()
        start_date_prc = pd.to_datetime(bbg.fetch_contract_parameter(self.bbg_ticker, 'CALENDAR_START_DATE').values[0][0])

        # Metadata to be saved
        self.country = bbg.fetch_contract_parameter(self.bbg_ticker, 'COUNTRY_ISO').iloc[0, 0].upper()
        self.exchange_symbol = bbg.fetch_contract_parameter(self.bbg_ticker, 'ID_EXCH_SYMBOL').iloc[0, 0]
        self.fh_ticker = 'eqs ' + self.country.lower() + ' ' + self.exchange_symbol.lower()
        self.asset_class = 'equity'
        self.type = 'stock'
        self.currency = bbg.fetch_contract_parameter(self.bbg_ticker, 'CRNCY').iloc[0, 0].upper()
        self.sector = bbg.fetch_contract_parameter(self.bbg_ticker, 'INDUSTRY_SECTOR').iloc[0, 0].lower()
        self.group = bbg.fetch_contract_parameter(self.bbg_ticker, 'INDUSTRY_GROUP').iloc[0, 0].lower()

        self.df_metadata = pd.DataFrame(data={'fh_ticker': self.fh_ticker,
                                              'asset_class': self.asset_class,
                                              'type': self.type,
                                              'exchange_symbol': self.exchange_symbol,
                                              'currency': self.currency,
                                              'country': self.country,
                                              'sector': self.sector,
                                              'group': self.group},
                                        index=[self.bbg_ticker])

        if isinstance(start_date_div, NaTType):
            start_date = start_date_prc
        else:
            start_date = min(start_date_div, start_date_prc)

        self.price = bbg.fetch_series(securities=bbg_ticker, fields=price_field, startdate=start_date, enddate=today)
        df = self._get_total_return_index()
        self.price = df[self.bbg_ticker].rename('Price')
        df['Price'] = self.price
        self.tr_index = df['Total Return Index'].rename('TR Index')
        self.quantity = df['Quantity'].rename('Quantity')
        self.df_ts = df[['Price', 'Dividend', 'Quantity', 'Total Return Index']]
        self.df_tracker = self._get_tracker_melted()
Пример #4
0
    def __init__(self, ticker, price_field='PX_LAST'):
        """
        Returns an object with the following atributes:
            - ticker: str with bloomberg ticker for the stock
            - dividends: DataFrame with dividend information. Its columns are 'Declared Date', 'Amount', 'Frequency',
                         'Type', 'Ex-Dividend Date', 'Payable Date', 'Record Date'
            - price: Series with the stock price
            - tr_index: Series with the total return index
            - quantity: amount of stocks held
            - ts_df: DataFrame with columns 'Price', 'Dividend', 'Quantity' and 'Total Return Index'
        :param ticker: str, Bloomberg ticker of the stock
        :param price_field: Price field to be used as settlement price
        """

        # TODO allow user to choose currency

        bbg = BBG()
        self.ticker = ticker
        today = pd.to_datetime('today')
        self.dividends = self._get_dividends(today, bbg)
        start_date_div = self.dividends['Ex-Dividend Date'].min()
        start_date_prc = pd.to_datetime(
            bbg.fetch_contract_parameter(self.ticker,
                                         'CALENDAR_START_DATE').values[0][0])

        if isinstance(start_date_div, NaTType):
            start_date = start_date_prc
        else:
            start_date = min(start_date_div, start_date_prc)

        self.price = bbg.fetch_series(securities=ticker,
                                      fields=price_field,
                                      startdate=start_date,
                                      enddate=today)
        df = self._get_total_return_index()
        self.price = df[self.ticker].rename('Price')
        df['Price'] = self.price
        self.tr_index = df['Total Return Index'].rename('TR Index')
        self.quantity = df['Quantity'].rename('Quantity')
        self.ts_df = df[[
            'Price', 'Dividend', 'Quantity', 'Total Return Index'
        ]]
Пример #5
0
                      enddate=end_date)
print(df)

# Grabs cashflow payments of corporate bonds
df = bbg.fetch_cash_flow('EI1436001 Govt', pd.to_datetime('03-jul-2017'))
print(df)

# Grabs weights of the components of an index
df = bbg.fetch_index_weights(index_name='IBOV Index',
                             ref_date=pd.to_datetime('03-jul-2017'))
print(df)
print(df.sum())

# Grabs all the contracts from a generic series
futures_list = bbg.fetch_futures_list(generic_ticker='TY1 Comdty')
print(futures_list)

# grabs the first notice date for each contract
df_fn = bbg.fetch_contract_parameter(securities=futures_list,
                                     field='FUT_NOTICE_FIRST')
print(df_fn)

# fetches fields with bulk data
df_bulk = bbg.fetch_bulk_data(index_name='AAPL US Equity',
                              field='PG_REVENUE',
                              ref_date=start_date)
print(df_bulk)

# fetches historical dividends
df_div = bbg.fetch_dividends('AAPL US Equity', end_date)
Пример #6
0
class BuildBondFutureTracker(object):

    futures_ticker_dict = {
        'US': 'TY',
        'GE': 'RX',
        'FR': 'OAT',
        'IT': 'IK',
        'JP': 'JB',
        'AU': 'XM',
        'UK': 'G ',
        'CA': 'CN'
    }

    fx_dict = {
        'GE': 'EURUSD Curncy',
        'UK': 'GBPUSD Curncy',
        'CA': 'CADUSD Curncy',
        'JP': 'JPYUSD Curncy',
        'AU': 'AUDUSD Curncy',
        'FR': 'EURUSD Curncy',
        'IT': 'EURUSD Curncy',
        'US': 'USD Curncy'
    }

    def __init__(self, country, start_date, end_date):

        self.bbg = BBG()
        self.country = country
        self.start_date = self._assert_date_type(start_date)
        self.end_date = self._assert_date_type(end_date)
        self.generic_tickers = [
            self.futures_ticker_dict[country] + str(x) + ' Comdty'
            for x in range(1, 4)
        ]
        self.df_generics = self._get_generic_future_series()
        self.df_uc = self._get_underlying_contracts()
        self.contract_list = self._get_contracts_list()
        self.df_fn = self._get_first_notice_dates()
        self.df_prices = self._get_all_prices()
        df_tracker = self._build_tracker()
        self.tr_index = df_tracker[['er_index']]
        self.df_roll_info = df_tracker[[
            'contract_rolling_out', 'roll_out_date', 'holdings'
        ]].dropna(how='any')

    def _get_generic_future_series(self):

        df = self.bbg.fetch_series(securities=self.generic_tickers,
                                   fields='PX_LAST',
                                   startdate=self.start_date,
                                   enddate=self.end_date)

        return df

    def _get_underlying_contracts(self):

        df = self.bbg.fetch_series(securities=self.generic_tickers,
                                   fields='FUT_CUR_GEN_TICKER',
                                   startdate=self.start_date,
                                   enddate=self.end_date)

        df = df.reindex(self.df_generics.index).fillna(method='ffill')

        return df

    def _get_contracts_list(self):

        contract_list = self.bbg.fetch_futures_list(
            generic_ticker=self.futures_ticker_dict[self.country] + '1 Comdty')

        return contract_list

    def _get_first_notice_dates(self):

        df = self.bbg.fetch_contract_parameter(
            securities=self.contract_list,
            field='FUT_NOTICE_FIRST').sort_values('FUT_NOTICE_FIRST')

        return df

    def _get_all_prices(self):

        tickers = self.contract_list + [self.fx_dict[self.country]]

        df = self.bbg.fetch_series(securities=tickers,
                                   fields='PX_LAST',
                                   startdate=self.start_date,
                                   enddate=self.end_date)

        df = df.reindex(self.df_generics.index).fillna(method='ffill')

        return df

    def _build_tracker(self):

        df_tracker = pd.DataFrame(index=self.df_generics.index,
                                  columns=[
                                      'contract_rolling_out', 'er_index',
                                      'roll_out_date', 'holdings'
                                  ])

        # set the values for the initial date
        dt_ini = self.df_uc.index[0]
        df_tracker.loc[dt_ini, 'er_index'] = 100
        contract_rolling_out = self.df_uc.loc[
            dt_ini,
            self.futures_ticker_dict[self.country] + '2 Comdty'] + ' Comdty'
        df_tracker.loc[dt_ini, 'contract_rolling_out'] = contract_rolling_out
        holdings = df_tracker.loc[dt_ini, 'er_index'] / (
            self.df_generics.loc[
                dt_ini, self.futures_ticker_dict[self.country] + '2 Comdty'] *
            self.df_prices[self.fx_dict[self.country]].loc[dt_ini])
        df_tracker.loc[dt_ini, 'holdings'] = holdings
        roll_out_date = self.df_fn.loc[df_tracker.loc[dt_ini,
                                                      'contract_rolling_out'],
                                       'FUT_NOTICE_FIRST'] - BDay(1)
        df_tracker.loc[dt_ini, 'roll_out_date'] = roll_out_date

        for d, dm1 in zip(df_tracker.index[1:], df_tracker.index[:-1]):

            df_tracker.loc[d, 'contract_rolling_out'] = contract_rolling_out

            price_dm1 = self.df_prices.loc[dm1, contract_rolling_out]
            price_d = self.df_prices.loc[d, contract_rolling_out]
            pnl = holdings * (price_d - price_dm1) * self.df_prices[
                self.fx_dict[self.country]].loc[d]

            if math.isnan(pnl):
                pnl = 0

            df_tracker.loc[d,
                           'er_index'] = df_tracker.loc[dm1, 'er_index'] + pnl

            if d >= roll_out_date.date():
                contract_rolling_out = (
                    self.df_uc.loc[d, self.futures_ticker_dict[self.country] +
                                   '2 Comdty'] + ' Comdty')
                df_tracker.loc[d,
                               'contract_rolling_out'] = contract_rolling_out

                holdings = df_tracker.loc[d, 'er_index'] / (
                    self.df_generics.loc[
                        d, self.futures_ticker_dict[self.country] + '2 Comdty']
                    * self.df_prices[self.fx_dict[self.country]].loc[d])
                df_tracker.loc[d, 'holdings'] = holdings

                roll_out_date = self.df_fn.loc[df_tracker.loc[
                    d, 'contract_rolling_out'], 'FUT_NOTICE_FIRST'] - BDay(1)
                df_tracker.loc[d, 'roll_out_date'] = roll_out_date

        return df_tracker

    @staticmethod
    def _assert_date_type(date):

        if type(date) is pd.Timestamp:
            date = date
        else:
            date = pd.to_datetime(date)

        return date
Пример #7
0
class FwdIRSTrackers(object):
    """
    Class for creating excess return indices for rolling interest rate swaps using data from bloomberg.
    At the start date, we assume we trade 100 notional 1M forward starting swaps with user provided maturity.
    We mark-to-market the position over the month and then roll it into the new 1M forward at the end of the month
    """

    # TODO: Include more currencies
    currency_bbg_code_dict = {
        'AUD': 'AD',
        'CAD': 'CD',
        'CHF': 'SF',
        'EUR': 'EU',
        'GBP': 'BP',
        'JPY': 'JY',
        'NZD': 'ND',
        'SEK': 'SK',
        'USD': 'US'
    }

    # TODO: Check these are correct
    currency_calendar_dict = {
        'USD': DayCounts('30E/360 ISDA', calendar='us_trading'),
        'AUD': DayCounts('ACT/365', calendar='us_trading'),
        'CAD': DayCounts('ACT/365', calendar='us_trading'),
        'CHF': DayCounts('30A/360', calendar='us_trading'),
        'EUR': DayCounts('30U/360', calendar='us_trading'),
        'GBP': DayCounts('ACT/365', calendar='us_trading'),
        'JPY': DayCounts('ACT/365F', calendar='us_trading'),
        'NZD': DayCounts('ACT/365', calendar='us_trading'),
        'SEK': DayCounts('30A/360', calendar='us_trading')
    }

    def __init__(self,
                 ccy='USD',
                 tenor=10,
                 start_date='2004-01-05',
                 end_date='today'):
        """
        Returns an object with the following attributes:
            - spot_swap_rates: Series with the rate for the spot starting swaps
            - fwd_swap_rates: Series with the rate for the 1M forward starting swaps
            - er_index: Series with the excess return index
        :param ccy_symbol: str, Currency symbol
        :param tenor: int, Tenor for the swap
        :param start_date: str, when the tracker should start
        :param end_date: str, when the tracker should end
        """

        self.ccy = ccy
        self.tenor = tenor
        self.start_date = (pd.to_datetime(start_date) + BDay(1)).date()
        self.end_date = pd.to_datetime(end_date).date()
        self.dc = self.currency_calendar_dict[ccy]

        self.bbg = BBG()
        self.spot_swap_rates = self._get_spot_swap_rates()
        self.fwd_swap_rates = self._get_1m_fwd_swap_rates()
        self.df_tracker = self._calculate_tr_index()

        self.country = self.bbg.fetch_contract_parameter(
            self.ticker_spot, 'COUNTRY_ISO').iloc[0, 0].upper()
        self.exchange_symbol = self.bbg.fetch_contract_parameter(
            self.ticker_fwd, 'TICKER').iloc[0, 0]
        self.fh_ticker = 'irs ' + self.country.lower() + ' ' + self.ccy.lower()

        self.df_metadata = pd.DataFrame(data={
            'fh_ticker': self.fh_ticker,
            'asset_class': 'fixed income',
            'type': 'swap',
            'currency': self.ccy.upper(),
            'country': self.country.upper(),
            'maturity': self.tenor,
            'roll_method': '1 month'
        },
                                        index=[self.ticker_spot])

        self.df_tracker = self._get_tracker_melted()

    def _calculate_tr_index(self):
        spot_rate_series = self.spot_swap_rates.iloc[:, 0].dropna()
        fwd_rate_series = self.fwd_swap_rates.iloc[:, 0].dropna()

        ts_df = pd.concat([
            spot_rate_series.to_frame('spot'),
            fwd_rate_series.to_frame('fwd_1m')
        ],
                          axis=1,
                          sort=True).fillna(method='ffill').dropna()

        er_index = pd.Series(index=ts_df.index)
        er_index.iloc[0] = 100

        start_date = er_index.index[0]
        fwd_swap_rate = ts_df.loc[start_date, 'fwd_1m'] / 100
        ref_swap_rate_d_minus_1 = fwd_swap_rate

        roll_date = self.dc.busdateroll(start_date + relativedelta(months=1),
                                        'modifiedfollowing')
        fwd_mat = self.dc.busdateroll(
            start_date + relativedelta(months=1 + self.tenor * 12),
            'modifiedfollowing')

        for d in er_index.index[1:]:
            current_fwd_swap_rate = ts_df.loc[d, 'fwd_1m'] / 100
            current_spot_swap_rate = ts_df.loc[d, 'spot'] / 100
            curr_fwd_mat = self.dc.busdateroll(
                d + relativedelta(months=1 + self.tenor * 12),
                'modifiedfollowing')
            curr_spot_mat = self.dc.busdateroll(
                d + relativedelta(months=self.tenor * 12), 'modifiedfollowing')

            w = 1 if d >= roll_date else self.dc.tf(
                curr_fwd_mat, fwd_mat) / self.dc.tf(curr_fwd_mat,
                                                    curr_spot_mat)

            ref_swap_rate = w * current_spot_swap_rate + (
                1 - w) * current_fwd_swap_rate

            # This is the present value of a basis point
            # Using the interpolated forward swap rate as an internal rate of return
            pv01 = np.sum([(1 / 2) * ((1 + ref_swap_rate / 2)**(-i))
                           for i in range(1, self.tenor * 2 + 1)])

            if np.isnan((ref_swap_rate_d_minus_1 - ref_swap_rate) * pv01):
                ret = 0
            else:
                ret = (ref_swap_rate_d_minus_1 - ref_swap_rate) * pv01

            er_index[d] = er_index[:d].iloc[-2] * (1 + ret)

            if d >= roll_date:
                roll_date = self.dc.busdateroll(d + relativedelta(months=1),
                                                'modifiedfollowing')
                fwd_mat = self.dc.busdateroll(
                    d + relativedelta(months=1 + self.tenor * 12),
                    'modifiedfollowing')
                ref_swap_rate_d_minus_1 = ts_df.loc[d, 'fwd_1m'] / 100
            else:
                ref_swap_rate_d_minus_1 = ref_swap_rate

        return er_index.to_frame('er_index')

    def _get_spot_swap_rates(self):
        if self.ccy == 'EUR':
            ticker = self.currency_bbg_code_dict[self.ccy] + 'SA' + str(
                self.tenor) + ' Curncy'
        elif self.ccy == 'NZD':
            ticker = self.currency_bbg_code_dict[self.ccy] + 'SWAP' + str(
                self.tenor) + ' Curncy'
        else:
            # The AUD is using the 6M floating leg case as default to be consistent with the forward ticker
            # The correct ticker is ADSW10Q Curncy 3M floating leg but then
            # you cannot use S0302FS 1M10Y BLC Curncy for the forward swap
            ticker = self.currency_bbg_code_dict[self.ccy] + 'SW' + str(
                self.tenor) + ' Curncy'

        bbg_raw_spot_data = self.bbg.fetch_series(securities=ticker,
                                                  fields='PX_LAST',
                                                  startdate=self.start_date,
                                                  enddate=self.end_date)

        self.ticker_spot = ticker

        bbg_raw_spot_data.columns = [self.ccy + str(self.tenor) + 'Y']
        bbg_raw_spot_data.index = pd.to_datetime(bbg_raw_spot_data.index)

        return bbg_raw_spot_data.dropna(how='all')

    def _get_1m_fwd_swap_rates(self):
        if self.ccy == 'EUR':
            ticker = self.currency_bbg_code_dict[self.ccy] + 'SAA' + str(
                self.tenor).zfill(2) + ' Curncy'
        elif self.ccy == 'GBP':
            ticker = self.currency_bbg_code_dict[self.ccy] + 'SWA' + str(
                self.tenor).zfill(2) + ' Curncy'
        elif self.ccy == 'AUD':
            # The AUD is using the 6M floating leg case as default to be consistent with the forward ticker
            # The correct ticker is ADSW10Q Curncy 3M floating leg but then
            # you cannot use S0302FS 1M10Y BLC Curncy for the forward swap
            ticker = 'S0302FS 1M' + str(self.tenor) + 'Y BLC Curncy'
        elif self.ccy == 'USD':
            ticker = self.currency_bbg_code_dict[self.ccy] + 'FS0A' + str(
                self.tenor) + ' Curncy'
        else:
            ticker = self.currency_bbg_code_dict[self.ccy] + 'FS0A' + str(
                self.tenor).zfill(2) + ' Curncy'

        bbg_fwd_data = self.bbg.fetch_series(securities=ticker,
                                             fields='PX_LAST',
                                             startdate=self.start_date,
                                             enddate=self.end_date)

        self.ticker_fwd = ticker

        bbg_fwd_data.columns = [self.ccy + str(self.tenor) + 'Y']
        bbg_fwd_data.index = pd.to_datetime(bbg_fwd_data.index)

        return bbg_fwd_data.dropna(how='all')

    def _get_tracker_melted(self):
        df = self.df_tracker[['er_index'
                              ]].rename({'er_index': self.ticker_spot}, axis=1)
        df['time_stamp'] = df.index.to_series()
        df = df.melt(id_vars='time_stamp',
                     var_name='fh_ticker',
                     value_name='value')
        df = df.dropna()

        return df
Пример #8
0
    'S0023Z 19Y BLC2 Curncy', 'S0023Z 23D BLC2 Curncy',
    'S0023Z 9Y BLC2 Curncy', 'S0023Z 17M BLC2 Curncy', 'S0023Z 1I BLC2 Curncy',
    'S0023Z 22Y BLC2 Curncy', 'S0023Z 28Y BLC2 Curncy',
    'S0023Z 2I BLC2 Curncy', 'S0023Z 30Y BLC2 Curncy',
    'S0023Z 31Y BLC2 Curncy', 'S0023Z 32Y BLC2 Curncy',
    'S0023Z 38Y BLC2 Curncy', 'S0023Z 39Y BLC2 Curncy',
    'S0023Z 40Y BLC2 Curncy', 'S0023Z 42D BLC2 Curncy',
    'S0023Z 48Y BLC2 Curncy'
]

df_bbg = bbg.fetch_series(tickers_zero_curve,
                          "PX_LAST",
                          startdate=pd.to_datetime('today'),
                          enddate=pd.to_datetime('today'))
df_bbg = df_bbg.transpose()
df_bbg_m = bbg.fetch_contract_parameter(tickers_zero_curve, "MATURITY")
''''
The Zero curve will be used on the interpolation, to discover the rate for a specific term.

'''

# fazendo a curva zero
zero_curve = pd.concat([df_bbg, df_bbg_m], axis=1,
                       sort=True).set_index('MATURITY').sort_index()
zero_curve = zero_curve.astype(float)
zero_curve = zero_curve.interpolate(method='linear',
                                    axis=0,
                                    limit=None,
                                    inplace=False,
                                    limit_direction='backward',
                                    limit_area=None,
    startdate=start_date,
    enddate=end_date)

# underlying contracts
df_uc = bbg.fetch_series(securities=['JB1 Comdty', 'JB2 Comdty', 'JB3 Comdty'],
                         fields='FUT_CUR_GEN_TICKER',
                         startdate=start_date,
                         enddate=end_date)
df_uc = df_uc.reindex(df_generics.index).fillna(method='ffill')

# all contracts
contract_list = bbg.fetch_futures_list(generic_ticker='JB1 Comdty')

# first notice date for the contract
df_fn = bbg.fetch_contract_parameter(
    securities=contract_list,
    field='FUT_NOTICE_FIRST').sort_values('FUT_NOTICE_FIRST')

# Grab all contract series
contract_list = contract_list + ['JPYUSD Curncy']
df_prices = bbg.fetch_series(securities=contract_list,
                             fields='PX_LAST',
                             startdate=start_date,
                             enddate=end_date)
df_prices = df_prices.reindex(df_generics.index).fillna(method='ffill')

# sets up the dataframe that will hold our results
df_tracker = pd.DataFrame(
    index=df_generics.index,
    columns=['contract_rolling_out', 'er_index', 'roll_out_date', 'holdings'])
Пример #10
0
class BondFutureTracker(object):

    futures_ticker_dict = {
        'US': 'TY',
        'DE': 'RX',
        'FR': 'OAT',
        'IT': 'IK',
        'JP': 'JB',
        'AU': 'XM',
        'GB': 'G ',
        'CA': 'CN'
    }

    fx_dict = {
        'DE': 'EURUSD Curncy',
        'GB': 'GBPUSD Curncy',
        'CA': 'CADUSD Curncy',
        'JP': 'JPYUSD Curncy',
        'AU': 'AUDUSD Curncy',
        'FR': 'EURUSD Curncy',
        'IT': 'EURUSD Curncy',
        'US': 'USD Curncy'
    }

    def __init__(self, country, start_date, end_date):

        assert country in list(
            self.futures_ticker_dict.keys()), 'Country not yet supported'
        self.bbg = BBG()
        self.country = country
        self.start_date = self._assert_date_type(start_date)
        self.end_date = self._assert_date_type(end_date)
        self.generic_tickers = [
            self.futures_ticker_dict[country] + str(x) + ' Comdty'
            for x in range(1, 4)
        ]
        self.df_generics = self._get_generic_future_series()
        self.df_uc = self._get_underlying_contracts()
        self.contract_list = self._get_contracts_list()
        self.df_fn = self._get_first_notice_dates()
        self.df_prices = self._get_all_prices()
        self.df_tracker = self._build_tracker()
        self.tr_index = self.df_tracker[['er_index']]
        self.fh_ticker = 'fibf ' + self.country.lower() + ' 10y'
        self.df_roll_info = self.df_tracker[[
            'contract_rolling_out', 'roll_out_date', 'holdings'
        ]].dropna(how='any')
        self.df_metadata = self._get_metadata()
        self.df_tracker = self._get_tracker_melted()

    def _get_tracker_melted(self):
        df = self.df_tracker[['er_index']].rename({'er_index': self.fh_ticker},
                                                  axis=1)
        df['time_stamp'] = df.index.to_series()
        df = df.melt(id_vars='time_stamp',
                     var_name='fh_ticker',
                     value_name='value')
        df = df.dropna()
        return df

    def _get_generic_future_series(self):

        df = self.bbg.fetch_series(securities=self.generic_tickers,
                                   fields='PX_LAST',
                                   startdate=self.start_date,
                                   enddate=self.end_date)

        return df

    def _get_underlying_contracts(self):

        df = self.bbg.fetch_series(securities=self.generic_tickers,
                                   fields='FUT_CUR_GEN_TICKER',
                                   startdate=self.start_date,
                                   enddate=self.end_date)

        df = df.reindex(self.df_generics.index).fillna(method='ffill')

        return df

    def _get_contracts_list(self):

        contract_list = self.bbg.fetch_futures_list(
            generic_ticker=self.futures_ticker_dict[self.country] + '1 Comdty')

        return contract_list

    def _get_first_notice_dates(self):

        df = self.bbg.fetch_contract_parameter(
            securities=self.contract_list,
            field='FUT_NOTICE_FIRST').sort_values('FUT_NOTICE_FIRST')

        return df

    def _get_all_prices(self):

        tickers = self.contract_list + [self.fx_dict[self.country]]

        df = self.bbg.fetch_series(securities=tickers,
                                   fields='PX_LAST',
                                   startdate=self.start_date,
                                   enddate=self.end_date)

        df = df.reindex(self.df_generics.index).fillna(method='ffill')

        return df

    def _build_tracker(self):

        df_tracker = pd.DataFrame(index=self.df_generics.index,
                                  columns=[
                                      'contract_rolling_out', 'er_index',
                                      'roll_out_date', 'holdings'
                                  ])

        # set the values for the initial date
        dt_ini = self.df_uc.dropna(how='all').index[0]
        df_tracker.loc[dt_ini, 'er_index'] = 100
        contract_rolling_out = self.df_uc.loc[
            dt_ini,
            self.futures_ticker_dict[self.country] + '2 Comdty'] + ' Comdty'
        df_tracker.loc[dt_ini, 'contract_rolling_out'] = contract_rolling_out
        holdings = df_tracker.loc[dt_ini, 'er_index'] / (
            self.df_generics.loc[
                dt_ini, self.futures_ticker_dict[self.country] + '2 Comdty'] *
            self.df_prices[self.fx_dict[self.country]].loc[dt_ini])
        df_tracker.loc[dt_ini, 'holdings'] = holdings
        roll_out_date = self.df_fn.loc[df_tracker.loc[dt_ini,
                                                      'contract_rolling_out'],
                                       'FUT_NOTICE_FIRST'] - BDay(1)
        df_tracker.loc[dt_ini, 'roll_out_date'] = roll_out_date

        for d, dm1 in zip(df_tracker.index[1:], df_tracker.index[:-1]):

            df_tracker.loc[d, 'contract_rolling_out'] = contract_rolling_out

            price_dm1 = self.df_prices.loc[dm1, contract_rolling_out]
            price_d = self.df_prices.loc[d, contract_rolling_out]
            pnl = holdings * (price_d - price_dm1) * self.df_prices[
                self.fx_dict[self.country]].loc[d]

            if math.isnan(pnl):
                pnl = 0

            df_tracker.loc[d,
                           'er_index'] = df_tracker.loc[dm1, 'er_index'] + pnl

            if d >= roll_out_date:
                contract_rolling_out = (
                    self.df_uc.loc[d, self.futures_ticker_dict[self.country] +
                                   '2 Comdty'] + ' Comdty')
                df_tracker.loc[d,
                               'contract_rolling_out'] = contract_rolling_out

                holdings = df_tracker.loc[d, 'er_index'] / (
                    self.df_generics.loc[
                        d, self.futures_ticker_dict[self.country] + '2 Comdty']
                    * self.df_prices[self.fx_dict[self.country]].loc[d])
                df_tracker.loc[d, 'holdings'] = holdings

                roll_out_date = self.df_fn.loc[df_tracker.loc[
                    d, 'contract_rolling_out'], 'FUT_NOTICE_FIRST'] - BDay(1)
                df_tracker.loc[d, 'roll_out_date'] = roll_out_date

        return df_tracker

    @staticmethod
    def _assert_date_type(date):

        if type(date) is pd.Timestamp:
            date = date
        else:
            date = pd.to_datetime(date)

        return date

    def _get_metadata(self):
        df = pd.DataFrame(index=[0],
                          data={
                              'fh_ticker':
                              self.fh_ticker,
                              'asset_class':
                              'fixed income',
                              'type':
                              'bond future',
                              'exchange_symbol':
                              self.futures_ticker_dict[self.country],
                              'currency':
                              'USD',
                              'country':
                              self.country,
                              'maturity':
                              10
                          })

        return df