def borrowing_capacity(self,as_of_date=None): ''' Reflects borrowing capacity for the month-end `as_of_date`. History is available going back back 12 months. Loan collateral reflects intraday processing of Mortgage Collateral Updates. Market value and all other data is as of prior business day close. :returns: TBD :rtype: dict of nested dicts ''' today = datetime.now().strftime('%Y-%m-%d') if as_of_date is None: as_of_date = today else: self._validate_date(as_of_date) if as_of_date != today: self.is_monthend(as_of_date) borrowing_capacity_endpoint = 'borrowing-capacity' params = urlencode({'as_of_date':as_of_date}) borrowing_capacity_url = urljoin( self.reports_url, borrowing_capacity_endpoint ) self.driver.get(borrowing_capacity_url + '?' + params) tables = WebDriverWait(self.driver, 15).until( EC.presence_of_all_elements_located( (By.XPATH,"//table[contains(@class,'report-table report-sub-table')" + " or contains(@class,'report-table report-parent-table')]") ) ) tree = lambda: defaultdict(tree) res = tree() for i,table in enumerate(tables): doc = html.fromstring(table.get_attribute('innerHTML')) headers = doc.xpath('.//th//text()') data = doc.xpath('.//td//text()') if i == 0: # hack - first table missing 2nd to last value in footer data = data[:-1] + [None] + data[-1:] record_size = len(headers) or 2 recs = partition(record_size,mapt(self.format_text,data)) section = 'capacity' if i in [1,2,3,5] else 'collateral' credit_program = 'standard' if i in range(4) else 'securities_backed' for rec in recs: collateral_type, *info = rec if headers: entry = dict(zip(headers[1:],info)) else: entry = info[0] res[credit_program][section][collateral_type] = entry return res
def sta_account(self,start_date,end_date): ''' Shows the Settlement/Transaction Account for a range of dates, with history going back 6 months. :param start_date: starting date of the report in "YYYY-mm-dd" format :param end_date: ending date of the report in "YYYY-mm-dd" format :type as_of_date: str :type end_date: str :returns: {'date1':[{'Reference Number':ref#, 'Description':desc...} {'Reference Number':ref#, 'Description':desc...}] 'date2':[...]} :rtype: defaultdict ''' sta_endpoint = 'settlement-transaction-account' bdate = self._validate_date(start_date) edate = self._validate_date(end_date) sta_url = urljoin(self.reports_url,sta_endpoint) self.driver.get(urljoin( sta_url, '?start_date={}&end_date={}'.format(bdate,edate))) table = self._webdriver_get_xpath(15,"//table[@class='report-table']") doc = html.fromstring(table.get_attribute('innerHTML')) td = doc.xpath('//tr//td') headers = doc.xpath('//th//text()') headers = [x.strip() for x in headers] sta_data = [x.getchildren()[0].text if x.getchildren() else x.text for x in td] sta_data = mapt(Client.format_text,sta_data) sta_data = itertools.groupby( partition(7,sta_data), lambda record: record[0] ) res = defaultdict(list) for date, records_per_date in sta_data: for record in records_per_date: res[date].append(dict(zip(headers[1:],record[1:]))) return res
def letters_of_credit(self): ''' Reflects current status of letters of credit. :returns: [{'LC Number':2081-10, 'Beneficiary': 'inst name', ...} {'LC Number':2081-10, 'Beneficiary': 'inst name', ...}...] :rtype: list of dicts ''' loc_url = urljoin(self.base_url,'letters-of-credit/manage') self.driver.get(loc_url) table = self._webdriver_get_xpath(15,'//table') doc = html.fromstring(table.get_attribute('innerHTML')) data = [self.format_text(d.strip()) for d in doc.xpath('//td//text()') if d != '\n'] headers = doc.xpath('//th//text()') return [dict(zip(headers,rec)) for rec in partition(len(headers),data)]
def historical_rates(self, start_date, end_date, collateral_type=None, credit_type=None): ''' Historical price indications as of 6:00 am PST on the date(s) referenced :param start_date: starting date of the report in "YYYY-mm-dd" format :param end_date: ending date of the report in "YYYY-mm-dd" format :param collateral_type: one of: Standard Credit Program, Securities-Backed Credit Program, or Settlemant/Transaction Acct. Rate :param credit_type: one of: Fixed Rate Credit, Variable Rate Credit, or Adjustable Rate Credit, where Adjustable Rate Credit may be either 1 Month Libor, 3 Month LIBOR, 6 Month LIBOR, or Daily Prime. Note that Daily Prime is only applicable for the Standard Credit Program collateral_type. :type as_of_date: str :type end_date: str :type collateral_type: str :type credit_type: str :returns: {'date1': {'maturity1':rate1,'maturity2':rate2} 'date2': {...} } :rtype: dict ''' self._validate_date(start_date) self._validate_date(end_date) collateral_type = collateral_type.lower() if collateral_type else None credit_type = credit_type.lower() if credit_type else None credit_types = ['frc','vrc','1m_libor','3m_libor', '6m_libor','daily_prime'] valid_pairings = set(itertools.chain( itertools.product(['standard'],credit_types), itertools.product(['sbc'],credit_types[0:-1]), [('sta',None)] )) if (collateral_type,credit_type) not in valid_pairings: raise AttributeError( "No matching entry for combination credit_type: {}".format( credit_type) + " and collateral_type: {}".format(collateral_type) ) historical_rates_endpoint = 'historical-price-indications' historical_rates_url = urljoin( self.reports_url, historical_rates_endpoint ) params = { 'start_date' :start_date, 'end_date' :end_date, 'historical_price_collateral_type' :collateral_type, 'historical_price_credit_type' :credit_type } params = urlencode(params) request_url = historical_rates_url + '?' + params self.driver.get(request_url) # wait for data to load - sloppy but couldn't find a common xpath # that all sub url's share. Maybe try to find one again later # but moving on for now time.sleep(10) # hopefully after 10 seconds the table referenced by the xpath # below is populated table = self._webdriver_get_xpath(0,"//table[contains(@class,'report-table')]") table_html = html.fromstring(table.get_attribute('innerHTML')) data = table_html[0].xpath('//td//text()') headers = table_html[0].xpath('//th//text()') headers = [x.strip() for x in headers] records = [x.strip() for x in data if x.strip()] record_count = len(headers) if credit_type in ['frc','vrc'] or collateral_type == 'sta': return {p[0]:dict(zip(headers[1:],p[1:])) for p in partition(record_count, mapt(self.format_text,records))} elif 'libor' in credit_type: return {p[0]:dict(zip(headers[2:],p[1:])) for p in partition(record_count-1, mapt(self.format_text,records))} elif credit_type == 'daily_prime': mats, headers = headers[0:4], headers[4:] data = [mapt(self.format_text,p) for p in partition(9,records)] res = {} for d in data: date, *others = d bench_and_spread = partition(2,others) per_maturity = zip(mats,bench_and_spread) daily_obs = {} for mat,bns in per_maturity: daily_obs[mat] = {'benchmark':bns[0],'spread':bns[1]} res[date] = daily_obs return res
def current_rates(self): ''' Reflects price indications as of 6:00 am PT on the current business day and STA rate as of the end of the prior business day. :returns: {'standard credit vrc':[{'Advance Maturity':'Overnight/Open', {'Advance Rate (%)':2.57}}] 'standard credit frc': [{...}]} :rtype: dict ''' current_rates_endpoint = 'current-price-indications' # dependent on table order in the website - if that changes, so should this tables = ['standard credit vrc', 'standard credit frc', 'standard adjustable rate credit', 'securities-backed credit vrc', 'securities-backed credit frc', 'securities-backed adjustable rate credit'] self.driver.get(urljoin(self.reports_url,current_rates_endpoint)) # wait for one of the tables to populate (they all do at the same time) self._webdriver_get_xpath(15,"//table[@id='DataTables_Table_1']/tbody") # then get outer div that wraps them (prior to waiting, all are empty) main_div = self._webdriver_get_xpath(15, "//div[@class='report report-price-indications " + "report-current-price-indications row']") div_html = html.fromstring(main_div.get_attribute('innerHTML')) rate_tables = {} for i, credit_type in enumerate(tables): table = div_html.xpath("//table[@id='DataTables_Table_{}']/tbody".format(i)) text = table[0].xpath('.//td//text()') records = [x.strip() for x in text if x.strip()] # dependent on table order in the website - if that changes, so should this if i in [0,1,3,4]: headers = ['Advance Maturity','Advance Rate (%)'] elif i == 2: headers = [ 'Advance Maturity', '1 Month LIBOR', '3 Month LIBOR', '6 Month LIBOR', 'Daily Prime' ] else: headers = [ 'Advance Maturity', '1 Month LIBOR', '3 Month LIBOR', '6 Month LIBOR' ] records = [dict(zip(headers,p)) for p in partition(len(headers),mapt(self.format_text,records))] rate_tables[credit_type] = records sta_rates = div_html.xpath(".//table[@class='report-table sta-rate-table " + "report-table-vertical-headers']//td//text()") rate_tables['Settlement/Transaction Account (STA)'] = {sta_rates[0]:sta_rates[1]} return rate_tables