Example #1
0
 def update_market_price(self, info_table, symbol_col, date=None):
     url_symbol = vlookup(info_table, self.symbol, symbol_col, 'ticker_url')
     if date is not None:
         # print('getting historical data for {} on {}'.format(self.symbol, date.strftime('%Y-%m-%d')))
         self.market_price = useful_functions.get_hist_price(
             url_symbol, date)
         self.market_price_time = date
     else:
         price_pair = get_last_price(url_symbol)
         self.market_price = price_pair[1]
         self.market_price_time = price_pair[0]
Example #2
0
 def update_name_changes(self, reference_df):
     name_changes = self.df[self.df['Action'] == 'NAC']
     print('{} rows of name changes detected'.format(len(name_changes)))
     if len(name_changes) > 0:
         for i in name_changes.index:
             i_symbol = vlookup(reference_df, self.df.loc[i, 'Symbol'],
                                'transfer_symbol', 'real_symbol')
             if i_symbol is None:
                 print('{} not found in reference table'.format(
                     self.df.loc[i, 'Symbol']))
             self.df.loc[i, 'Symbol'] = i_symbol
Example #3
0
 def update_splits(self, reference_df):
     splits = self.df[self.df['Action'] == 'REV']
     print('{} rows of reverse splits/splits detected'.format(len(splits)))
     if len(splits) > 0:
         for i in splits.index:
             i_symbol = vlookup(reference_df, self.df.loc[i, 'Symbol'],
                                'transfer_symbol', 'real_symbol')
             if i_symbol is None:
                 print('{} not found in reference table'.format(
                     self.df.loc[i, 'Symbol']))
             self.df.loc[i, 'Symbol'] = i_symbol
Example #4
0
 def update_market_price(self, info_table, symbol_col, date=None):
     url_symbol = vlookup(info_table, self.underlying_symbol, symbol_col,
                          'ticker_url')
     lookup_instrument = vlookup(info_table, self.underlying_symbol,
                                 symbol_col, 'instrument')
     if date is not None:
         self.underlying_market_price = useful_functions.get_hist_price(
             self.underlying_symbol, date)
         self.underlying_market_price_time = date
     else:
         price_pair = get_last_price(url_symbol)
         self.underlying_market_price = price_pair[1]
         self.underlying_market_price_time = price_pair[0]
     # the market price of the option is intrinsic value only due to difficulties of getting market value of options
     if self.option_type == 'Call':
         self.market_price = max(0, self.underlying_market_price -
                                 self.strike) * self.num_shares
     else:
         self.market_price = max(
             0,
             self.strike - self.underlying_market_price) * self.num_shares
     self.market_price_time = self.underlying_market_price_time
Example #5
0
 def update_inkind_transfer(self, reference_df):
     inkind_transfers = self.df[(self.df['Activity Type'] == 'Transfers')
                                & (~pd.isna(self.df['Symbol']))]
     print('{} rows of in-kind transfers detectted'.format(
         len(inkind_transfers)))
     if len(inkind_transfers) > 0:
         for i in inkind_transfers.index:
             i_currency = self.df.loc[i, 'Currency']
             if i_currency == 'CAD':
                 self.df.loc[i, 'Symbol'] = self.df.loc[i, 'Symbol'] + '.TO'
             elif i_currency == 'USD':
                 self.df.loc[i,
                             'Symbol'] = vlookup(reference_df,
                                                 self.df.loc[i, 'Symbol'],
                                                 'transfer_symbol',
                                                 'real_symbol')
Example #6
0
 def update_security_info(self, info_table, symbol_col):
     self.asset_class = vlookup(info_table, self.underlying_symbol,
                                symbol_col, 'asset_class')
     self.region = vlookup(info_table, self.underlying_symbol, symbol_col,
                           'region')
Example #7
0
 def update_security_info(self, info_table, symbol_col):
     self.instrument = vlookup(info_table, self.symbol, symbol_col,
                               'instrument')
     self.asset_class = vlookup(info_table, self.symbol, symbol_col,
                                'asset_class')
     self.region = vlookup(info_table, self.symbol, symbol_col, 'region')
Example #8
0
def questrade_transaction_to_sec(transaction_df, split_reference=None):
    '''
    Parameters
    ----------
    transaction_df : DataFrame
        the dataframe exported by questrade

    split_reference : DataFrame, optional
        a reference dataframe for stock splits, default None

    Returns
    -------
    two dictionaries

    '''

    l = len(transaction_df)
    holdings_dict = {'CAD': 0, 'USD': 0}
    security_dict = {}
    for i in range(l):
        if (i % 50) == 0:
            print('processing row {}'.format(i))
        i_row = transaction_df.loc[i, ]
        i_transaction_date = i_row['Transaction Date']
        i_action = i_row['Action']
        i_symbol = i_row['Symbol']
        i_description = i_row['Description']
        i_quantity = i_row['Quantity']
        i_price = i_row['Price']
        i_gross_amount = i_row['Gross Amount']
        i_commission = i_row['Commission']
        i_net_amount = i_row['Net Amount']
        i_currency = i_row['Currency']
        i_activity = i_row['Activity Type']

        # different cases
        # cash deposit
        if i_activity == 'Deposits':
            holdings_dict[i_currency.upper()] += i_net_amount

        # dividends operate the same way as deposits
        elif i_activity == 'Dividends':
            holdings_dict[i_currency.upper()] += i_net_amount

        # fx conversion is like two deposits at once
        elif i_activity == 'FX conversion':
            holdings_dict[i_currency.upper()] += i_net_amount

        # the opposite of deposits
        elif i_activity == 'Withdrawals':
            holdings_dict[i_currency.upper()] += i_net_amount

        # buying or selling securities
        elif i_activity == 'Trades':
            # first see if it is an option
            i_description_split = i_description.split(' ')
            if (i_description_split[0] == 'PUT') or (i_description_split[0]
                                                     == 'CALL'):  # option
                i_option = description_to_option(i_description, i_currency)
                i_option_symbol = i_option.symbol
                if i_option_symbol not in security_dict.keys():
                    security_dict[i_option_symbol] = i_option

                i_option = security_dict[i_option_symbol]
                i_option.new_trade(i_quantity, i_price * 100,
                                   abs(i_commission))

                if i_option.liquidated:
                    del security_dict[i_option_symbol]
                else:
                    security_dict[i_option_symbol] = i_option
            else:  # not an option
                if i_symbol not in security_dict.keys():
                    i_security = Security(i_symbol, i_currency)
                    security_dict[i_symbol] = i_security

                i_security = security_dict[i_symbol]
                i_security.new_trade(i_quantity, i_price, abs(i_commission))

                if i_security.liquidated:
                    del security_dict[i_symbol]
                else:
                    security_dict[i_symbol] = i_security

            holdings_dict[i_currency.upper()] += i_net_amount

        # cash or in-knd transfer to and from another investment account
        elif i_activity == 'Transfers':
            if i_action == 'TF6':  # transfer in
                if (i_symbol != '') and (
                        not pd.isna(i_symbol)):  # in-kind transfer of shares
                    if (i_currency == 'CAD') and ('.TO' not in i_symbol):
                        i_symbol = i_symbol + '.TO'
                    i_price = useful_functions.get_hist_price(
                        i_symbol, i_transaction_date)
                    if i_symbol not in security_dict.keys():
                        i_security = Security(i_symbol, i_currency)
                        security_dict[i_symbol] = i_security
                    i_security = security_dict[i_symbol]
                    i_security.new_trade(
                        i_quantity, i_price,
                        0)  # no commission for in-kind transfer
                else:  # cash transfer
                    holdings_dict[i_currency.upper()] += i_net_amount
            elif i_action == 'TFO':  # trasnfer out
                if (i_symbol != '') and (
                        not pd.isna(i_symbol)):  # transferring securities
                    if i_symbol not in security_dict.keys():
                        print('transferring out non-existent security')
                        return
                    i_security = security_dict[i_symbol]
                    i_security.new_trade(i_quantity, i_price,
                                         abs(i_commission))

                    if i_security.liquidated:
                        del security_dict[i_symbol]
                    else:
                        security_dict[i_symbol] = i_security
                else:  # transferring out cash
                    holdings_dict[i_currency.upper()] += i_net_amount

        # other activities
        elif i_activity == 'Other':
            if i_action == 'EXP':  # option expiry
                i_option = description_to_option(i_description, i_currency)
                i_option_symbol = i_option.symbol
                del security_dict[i_option_symbol]
            elif i_action == 'GST':  # tax on fees
                holdings_dict[i_currency.upper()] += i_net_amount
            elif i_action == 'BRW':  # journalling
                if i_quantity < 0:
                    i_security = security_dict[i_symbol]
                    symbol_to = journal_symbol_dest(
                        i_symbol, i_currency)  # need to define
                    i_security.journal(symbol_to, i_transaction_date)
                    del security_dict[i_symbol]
                    if symbol_to not in security_dict.keys():
                        security_dict[symbol_to] = i_security
                    else:
                        existing_security = security_dict[symbol_to]
                        existing_security.new_trade(i_security.quantity,
                                                    i_security.average_cost,
                                                    i_security.commission)
                        security_dict[symbol_to] = existing_security
            elif i_action == 'ADJ':  # option adjustment because of splits
                if i_quantity < 0:
                    # first find the new underlying symbol
                    counter_adj = transaction_df[
                        (transaction_df['Action'] == 'ADJ')
                        & (transaction_df['Transaction Date'] ==
                           i_transaction_date) &
                        (transaction_df['Quantity']
                         == -1 * i_quantity)].reset_index()
                    new_underlying_symbol = description_to_option(
                        counter_adj.loc[0, 'Description'],
                        counter_adj.loc[0, 'Currency']).underlying_symbol

                    # then find the mutliplier that should be applied to the strike/share number due to the split
                    lookup_date = datetime(i_transaction_date.year,
                                           i_transaction_date.month,
                                           i_transaction_date.day)
                    multiplier = vlookup(split_reference, lookup_date, 'date',
                                         'multiplier')

                    # get the current held option and manipulate it
                    old_symbol = description_to_option(i_description,
                                                       i_currency).symbol
                    i_option = security_dict[old_symbol]
                    i_option.adjust_for_split(multiplier,
                                              new_underlying_symbol)

                    # make the change
                    del security_dict[old_symbol]
                    security_dict[i_option.symbol] = i_option

        # fees and rebates
        elif i_activity == 'Fees and rebates':
            if i_action == 'FCH':  # fees
                holdings_dict[i_currency.upper()] += i_net_amount
            else:
                pass

        # corporate actions, e.g. splits, name changes
        elif i_activity == 'Corporate actions':
            if i_action == 'CIL':  # cash in lieu
                holdings_dict[i_currency.upper()] += i_net_amount
            elif i_action == 'REV':  # reverse split
                if i_quantity < 0:
                    i_security = security_dict[i_symbol]
                    counter_split = transaction_df[
                        (transaction_df['Action'] == 'REV')
                        & (transaction_df['Transaction Date'] ==
                           i_transaction_date) &
                        (transaction_df['Quantity'] > 0)]
                    new_quantity = int(counter_split['Quantity'])
                    lookup_date = datetime(i_transaction_date.year,
                                           i_transaction_date.month,
                                           i_transaction_date.day)
                    ratio = 1 / vlookup(split_reference, lookup_date, 'date',
                                        'multiplier')
                    i_security.reverse_split(ratio, new_quantity)
                    security_dict[i_symbol] = i_security
            elif i_action == 'NAC':  # name change
                pass

        # any activities not encountered before
        else:
            print('a new activity not encountered before, exiting...')
            return

    return security_dict, holdings_dict