def testAverageRating(self): positions = getPortfolioPositions('19437', '20200429', 'test') blpData = getBlpData('20200429', 'test') securitiesWithRatings = compose( list , partial(map, lambda p: (getAverageRatingScore(blpData, p), p)) , partial(map, lambda t: t[1]) , partial(filter, lambda t: ratingsApplicable(t[0])) , lambda blpData, positions: \ map(lambda p: (getAssetType(blpData, p), p), positions) )(blpData, positions) # There are 154 bonds (155 bonds, but one with special case override) self.assertEqual(154, len(securitiesWithRatings)) # Has 3 credit ratings self.assertEqual(11, firstOf( lambda t: t[1]['InvestID'] == 'XS2114413565' , securitiesWithRatings)[0]) # Has 2 credit ratings self.assertEqual(11, firstOf( lambda t: t[1]['InvestID'] == 'USY70902AB04' , securitiesWithRatings)[0]) # Has 1 credit ratings self.assertEqual(13, firstOf( lambda t: t[1]['InvestID'] == 'XS2127809528' , securitiesWithRatings)[0]) # Has no credit ratings self.assertEqual(0, firstOf( lambda t: t[1]['InvestID'] == 'XS2021226985' , securitiesWithRatings)[0])
def testFile(self): """ Randomly check a bond's purchase cost and yield at cost """ dataFile = join(get_current_path(), 'samples', 'test_historical' , 'CLO Holdings 2019.06.28.xlsx') historicalData = toDictionary(getRawPositions(fileToLines(dataFile))) file = join(get_current_path(), 'samples', 'test_historical' , '12229 tax lot 201906.xlsx') rows = list(fileToTSCF(historicalData, file)) self.assertEqual(154, len(rows)) # 12229 has 77 positions # therefore generates 2 x 77 rows bond1_cost = lambda L: True if L[0]=='CD022' and L[2]=='HK0000226404' else False bond1_yield = lambda L: True if L[0]=='CD021' and L[2]=='HK0000226404' else False item = firstOf(bond1_cost, rows) self.assertTrue(item != None) self.assertEqual(item[3], '12229') self.assertAlmostEqual(item[4], 99.027) item = firstOf(bond1_yield, rows) self.assertTrue(item != None) self.assertEqual(item[3], '12229') self.assertAlmostEqual(item[4], 6.2)
def groupToTicket(group): """ [List] group of tickets => [Dictionary] ticket """ isActiveTicket = lambda g: \ g[0]['Repo Sta'] == 'Active' getMrcTicket = lambda g: \ firstOf(lambda el: el['Type'] == 'MRC', g) getRtTicket = lambda g: \ firstOf(lambda el: el['Type'] == 'RT', g) getKmrTicket = lambda g: \ firstOf(lambda el: el['Type'] == 'KMR', g) getCrTicket = lambda g: \ firstOf(lambda el: el['Type'] == 'CR', g) return \ mergeDictionary(getRtTicket(group), {'Tkt #': getMrcTicket(group)['Tkt #']}) \ if isActiveTicket(group) else \ mergeDictionary(getCrTicket(group), {'Orig Tkt': getKmrTicket(group)['Orig Tkt']})
def cashEntry(lineItems): """ [List] lineItems => [Tuple] (currency, amount) """ isFloat = lambda x: True if isinstance(x, float) else False isCurrencyString = lambda x: True if isinstance(x, str) \ and len(x) > 6 and x[0] == '(' \ and x[6] == ')' \ else False amount = firstOf(isFloat, lineItems) currencyString = firstOf(isCurrencyString, lineItems) if amount == None or currencyString == None: raise ValueError('cashEntry(): cannot parse cash entry: {0}'.format(lineItems)) return (currencyString.strip()[2:5], amount)
def getPosition(lines): """ [Iterable] lines => [Iterable] positions lines: from the Excel worksheet containing the holdings Return an iterable object on the list of holding positions. Each position is a dictionary. """ nonEmptyString = lambda s: s != '' position = lambda headers, values: dict(zip(headers, values)) nonEmptyLine = lambda L: False if len(L) == 0 else nonEmptyString(L[0]) headerLine = lambda L: L[0] == 'Trader Name' if len(L) > 0 else False nomuraOnly = lambda p: p['Trader Name'] == '40017-B' toDateString = lambda f: fromExcelOrdinal(f).strftime('%d%m%Y') def updateValue(p): p['As of Date'] = toDateString(p['As of Date']) p['Settlement Date'] = toDateString(p['Settlement Date']) return p headers = list(takewhile(nonEmptyString, firstOf(headerLine, lines))) return map( updateValue, filter(nomuraOnly, map(partial(position, headers), takewhile(nonEmptyLine, lines))))
def testRawPosition(self): inputFile = join(getCurrentDirectory(), 'samples', 'Holding _22102019.xlsx') dt, positions = (lambda t: (t[0], list(t[1])))(getPositions(inputFile)) self.assertEqual('2019-10-22', dt) self.assertEqual(48, len(positions)) self.verifyRawPosition(firstOf( lambda p: p['Security Name'] == 'EASY TACTIC LTD 9.125% 28/07/2022'\ , positions))
def testGetCashFromBalancenActivityFiles(self): activityFile = join(getCurrentDirectory(), 'samples', 'Cash Stt _21042020_activity.xlsx') balanceFile = join(getCurrentDirectory(), 'samples', 'Cash Stt _21042020.xlsx') date, positions = getCashFromBalancenActivityFiles(balanceFile, activityFile) self.assertEqual('2020-04-21', date) positions = list(positions) self.assertEqual(3, len(positions)) usd = firstOf(lambda p: p['currency'] == 'USD', positions) self.assertEqual('JIC INTERNATIONAL LIMITED - CLFAMC', usd['portfolio']) self.assertEqual('2020-04-21', usd['date']) self.assertAlmostEqual(207111.65, usd['balance']) hkd = firstOf(lambda p: p['currency'] == 'HKD', positions) self.assertAlmostEqual(579, hkd['balance']) eur = firstOf(lambda p: p['currency'] == 'EUR', positions) self.assertAlmostEqual(0, eur['balance'])
def testOutputData2(self): inputFile = join(getCurrentDirectory(), 'samples', 'Holding _24102019.xlsx') postfix, data = (lambda t: (t[0], list(t[1])))(toOutputData(inputFile)) self.assertEqual('_nomura_2019-10-24_position', postfix) self.assertEqual(49, len(data)) self.assertEqual(getHoldingHeaders(), data[0]) self.verifyOutputLine2(firstOf( lambda line: line[4] == ''\ , map(list, data)))
def testFolder(self): """ Read a folder and pick another position to test. """ rows = list(folderToTSCF(join(get_current_path() , 'samples', 'test_historical'))) self.assertEqual(240, len(rows)) # 12229 has 77 bond positions, # 12366 has 43 bond positions, # so total 120 positions and 240 rows bond2_cost = lambda L: True if L[0]=='CD022' and L[2]=='US06428YAA47' and L[3]=='12366' else False bond2_yield = lambda L: True if L[0]=='CD021' and L[2]=='US06428YAA47' and L[3]=='12366' else False item = firstOf(bond2_cost, rows) self.assertTrue(item != None) self.assertAlmostEqual(item[4], 100) item = firstOf(bond2_yield, rows) self.assertTrue(item != None) self.assertAlmostEqual(item[4], 5.9)
def testAllFiles(self): files = \ [ '01 cash only.xls' , '02 cash multiple bond.xls' , '03 cash equity.xls' , '04 cash usd bond.xls' , '05 cash multiple bond.xls' , '06 multiple cash multiple bond.xls' , '07 multiple cash multiple bond.xls' ] countHTMPositions = partial(countPositions, lambda p: p['AssetType'] == 'HTMBond') countAllHTMPositions = lambda files: compose( list, partial(map, countHTMPositions), partial(map, readFile), partial(map, lambda f: join(getCurrentDirectory(), 'samples', f)))( files) self.assertEqual([0, 11, 0, 11, 51, 75, 74], countAllHTMPositions(files)) htmPositions = compose( list, getHTMPositionsFromFiles, partial( map, lambda f: join(getCurrentDirectory(), 'samples', f)))(files) self.assertEqual(222, len(htmPositions)) # Test consolidated position self.verifyUSDHTMBondPosition2( firstOf( lambda p: p['Portfolio'] == '12630' and p['ISIN'] == 'US55608KAD72', htmPositions)) # Test ISIN code swap self.verifyUSDHTMBondPosition3( firstOf( lambda p: p['Portfolio'] == '12734' and p['Description'] == 'DBANFB12014 Dragon Days Ltd 6.0%', htmPositions))
def testDIFAssetType(self): positions = list(getPortfolioPositions('19437', '20200429', 'test')) blpData = getBlpData('20200429', 'test') # USD cash on hand position isUSDCash = lambda x: \ x['InvestID'] == 'USD' and int(x['Quantity']) == 8183675 self.assertEqual( ('Cash', ) , getAssetType(blpData, firstOf(isUSDCash, positions))) # Cash payable position isHKDCashPayable = lambda x: \ x['InvestID'] == 'HKD' and int(x['Quantity']) == -1804761 self.assertEqual( ('Cash', ) , getAssetType(blpData, firstOf(isHKDCashPayable, positions))) # Equity position isEquityPosition = lambda x: x['InvestID'] == '1299 HK' self.assertEqual( ('Equity', 'Listed Equities') , getAssetType(blpData, firstOf(isEquityPosition, positions))) # The bond: T V2.875 PERP B isBondPosition = lambda x: x['InvestID'] == 'XS2114413565' self.assertEqual( ('Fixed Income', 'Corporate') , getAssetType(blpData, firstOf(isBondPosition, positions))) # The bond: POSABK V4.5 PERP, the special case, treated as equity in 19437 isBondPosition2 = lambda x: x['InvestID'] == 'XS1684793018 Perfshs' self.assertEqual( ('Equity', 'Listed equities') , getAssetType(blpData, firstOf(isBondPosition2, positions))) # The callable bond: BCHINA V3.6 PERP isCallableBondPosition = lambda x: x['InvestID'] == 'XS2125922349' self.assertEqual( ('Fixed Income', 'Additional Tier 1, Contingent Convertibles') , getAssetType(blpData, firstOf(isCallableBondPosition, positions))) # The iShares A50 China ETF isA50Fund = lambda x: x['InvestID'] == '2823 HK' self.assertEqual( ('Fund', 'Exchange Traded Funds') , getAssetType(blpData, firstOf(isA50Fund, positions))) # The LINK REIT (823 HK is treated as special case) isREITFund = lambda x: x['InvestID'] == '823 HK' self.assertEqual( ('Equity', 'Listed equities') , getAssetType(blpData, firstOf(isREITFund, positions)))
def currencyFromName(name): """ Extract the currency from the security name [String] name => [String] currency security name looks like: HUI XIAN REAL ESTATE INVESTMENT TRUST REIT CNY PICC PROPERTY & CASUALTY CO LTD COMMON STOCK HKD 1 1MDB ENERGY LTD NOTES FIXED 5.99% 11/MAY/2022 USD 100000 """ isCurrency = lambda x: x in ['HKD', 'USD', 'CNY', 'SGD', 'JPY', 'EUR'] return firstOf(isCurrency, name.split()[-2:])
def testConsolidate(self): inputFile = join(getCurrentDirectory(), 'samples', 'poll_result.xlsx') records = compose( list , consolidate , getRawHoldingPositions )(inputFile) self.assertEqual(44, len(records)) self.assertEqual(1, len(list(filter( lambda p: p['Email'] == '*****@*****.**' , records)))) self.assertEqual(1, len(list(filter( lambda p: p['Email'] == '*****@*****.**' , records)))) self.assertEqual( 'Surface laptop (Intel i5/8GB RAM/128GB SSD)' , firstOf( lambda p: p['Email'] == '*****@*****.**' , records)['Item'])
def getPositionsFromLines(lines): """ [Iterator] lines => [Iterator] positions """ getHeaderLine = lambda lines: \ firstOf(lambda line: len(line) > 0 and line[0] == 'Trader Name', lines) getHeaderFromLine = compose(list, partial(takewhile, lambda s: s != '')) toPosition = lambda headers, line: \ dict(zip(headers, line)) return compose( lambda t: map(partial(toPosition, getHeaderFromLine(t[0])), t[1]) , lambda t: lognRaise('getPositionsFromLines(): failed to get header line') \ if t[0] == None else t , lambda lines: (getHeaderLine(lines), lines) )(lines)
def folderToTSCF(folder): """ [String] folder => [Iterable] TSCF rows folder: a folder containing the historical data file and all the Geneva tax lot appraisal report files (Excel). """ isHistoricalDataFile = lambda f: f.split('\\')[-1].startswith( 'CLO Holdings') dataFile = firstOf(isHistoricalDataFile, getExcelFiles(folder)) if (dataFile == None): print('folderToTSCF(): data file not found') raise ValueError else: print('folderToTSCF(): data file: {0}'.format(dataFile)) historicalData = toDictionary(getRawPositions(fileToLines(dataFile))) glueTogether = lambda L: reduce(chain, L, []) return glueTogether( map(partial(fileToTSCF, historicalData), filterfalse(isHistoricalDataFile, getExcelFiles(folder))))
# coding=utf-8 # import unittest2 from risk_report.lqa import createLqaPositions from risk_report.data import getPositionDate from risk_report.utility import getCurrentDirectory from functools import partial from utils.iter import firstOf from toolz.functoolz import compose from os.path import join findById = lambda id, positions: \ firstOf(lambda p: p['Id'] == id, positions) findByName = lambda name, positions: \ firstOf(lambda p: p['Name'] == name, positions) class TestLqa(unittest2.TestCase): def __init__(self, *args, **kwargs): super(TestLqa, self).__init__(*args, **kwargs)