def testGetRepoTransactionHistory(self): #-- preprocess: add 2 repo master and 6 transaction master1 = self._get_test_repo_master() addRepoMaster(master1) transaction1 = self._get_test_transaction() addRepoTransaction(transaction1) #-- 1. invalid input value #-- 1.1 non-string value with self.assertRaises(ValueError): getRepoTransactionHistory(300734) #-- 2. valid input value #-- 2.1 empty result res = getRepoTransactionHistory("300734-") self.assertEqual(0, len(res)) #-- 2.2 has result res = getRepoTransactionHistory("300734") self.assertEqual(1, len(res)) self.assertEqual('300734', res[0]['TransactionId']) self.assertEqual('open', res[0]['Action']) self.assertEqual('2018-08-27', res[0]['Date']) self.assertEqual(0.95, res[0]['InterestRate']) try: datetime.strptime(res[0]['TimeStamp'], "%Y-%m-%d %H:%M:%S") except ValueError: raise ValueError("Incorrect data format, should be YYYY-MM-DD")
def testCloseRepoTransaction(self): #-- 1. create repo_master, repo_transaction and close the transaction normally master = self._get_test_repo_master() addRepoMaster(master) transaction = self._get_test_transaction() addRepoTransaction(transaction) close_transaction = { "UserTranId1": "300734", "ActualSettleDate": "2018-08-31T00:00:00" } self.assertEqual(closeRepoTransaction(close_transaction), 0) session = sessionmaker(bind=DBConn.get_db(self.unittest_dbmode))() transaction_result = session.query(RepoTransaction) \ .filter_by(transaction_id=close_transaction['UserTranId1']) \ .first() self.assertEqual(Constants.REPO_TRANS_STATUS_CLOSE, transaction_result.status) session.close() #-- 2. close a closed transaction again. It shall be allowed try: closeRepoTransaction(close_transaction) except CloseCanceledRepoTransactionError: self.fail( "Close a closed transaction again shall be allowed. But an exception is throw" ) #-- 3. close an unknown transaction to confirm RepoTransactionNotExistError will throw unknown_transaction = { "UserTranId1": "300734x", "ActualSettleDate": "2018-08-31T00:00:00" } with self.assertRaises(RepoTransactionNotExistError): closeRepoTransaction(unknown_transaction)
def testRerateRepoTransaction(self): #-- 1. create repo_master, repo_transaction and rerate the transaction normally master = self._get_test_repo_master() addRepoMaster(master) transaction = self._get_test_transaction() addRepoTransaction(transaction) rerate_transaction = { "UserTranId1": "300734", "RateTable": { "Rate": "1.6565", "RateDate": "2020-12-31T00:00:00" } } self.assertEqual(rerateRepoTransaction(rerate_transaction), 0) session = sessionmaker(bind=DBConn.get_db(self.unittest_dbmode))() transaction_result = session.query(RepoTransaction) \ .filter_by(transaction_id=rerate_transaction['UserTranId1']) \ .first() self.assertEqual(1.6565, transaction_result.interest_rate) session.commit() #-- 2. rerate the transaction again and shall have no problem rerate_transaction = { "UserTranId1": "300734", "RateTable": { "Rate": "1.4992", "RateDate": "2020-12-31T00:00:00" } } self.assertEqual(rerateRepoTransaction(rerate_transaction), 0) transaction_result = session.query(RepoTransaction) \ .filter_by(transaction_id=rerate_transaction['UserTranId1']) \ .first() self.assertEqual(1.4992, transaction_result.interest_rate) session.close() #-- 3. rerate the transaction with invalid RateTable invalid_transaction = { "UserTranId1": "300734", "RateTable": { "Rate": "1.6565x", "RateDate": "2020-12-31T00:00:00" } } with self.assertRaises(ValueError): rerateRepoTransaction(invalid_transaction) #-- 4. rerate an unknown transaction to confirm RepoTransactionNotExistError will throw unknown_transaction = { "UserTranId1": "300734x", "RateTable": { "Rate": "1.5", "RateDate": "2020-12-31T00:00:00" } } with self.assertRaises(RepoTransactionNotExistError): rerateRepoTransaction(unknown_transaction)
def addRepo(trade): try: logger.debug( 'saveRepoTradeFileToDB(): add repo transaction id {0}'.format( trade.get('UserTranId1', ''))) if isRepoOpenTrade(trade): addRepoTransaction( keepKeys([ 'TransactionType', 'UserTranId1', 'Portfolio', 'LocationAccount', 'Investment', 'EventDate', 'SettleDate', 'OpenEnded', 'ActualSettleDate', 'Quantity', 'CounterInvestment', 'Price', 'NetCounterAmount', 'RepoName', 'Coupon', 'LoanAmount', 'Broker' ], trade)) return 1 elif isRepoCloseTrade(trade): closeRepoTransaction( keepKeys(['UserTranId1', 'ActualSettleDate'], trade)) return 1 elif isRepoCancelTrade(trade): cancelRepoTransaction(keepKeys(['UserTranId1'], trade)) return 1 else: logger.error( 'saveRepoTradeFileToDB(): invalid trade type'.format( trade.get('TransactionType', ''))) return 0 except RepoTransactionAlreadyExistError: logger.warning( 'saveRepoTradeFileToDB(): repo transaction {0} already exists'. format(trade.get('UserTranId1', ''))) return 0 except: logger.exception('saveRepoTradeFileToDB():') return 0
def testGetUserTranIdsFromRepoName(self): #-- preprocess: add 2 repo master and 6 transaction master1 = self._get_test_repo_master() addRepoMaster(master1) master2 = self._get_test_repo_master() master2["Code"] = "MMRPE420BSS" addRepoMaster(master2) transaction1 = self._get_test_transaction() addRepoTransaction(transaction1) transaction2 = self._get_test_transaction() transaction2["UserTranId1"] = "300735" addRepoTransaction(transaction2) transaction2 = self._get_test_transaction() transaction2["UserTranId1"] = "300736" transaction2["RepoName"] = "MMRPE420BSS" addRepoTransaction(transaction2) #-- 1. invalid input value #-- 1.1 non-string value with self.assertRaises(ValueError): getUserTranIdsFromRepoName(300734) #-- 2. valid input value #-- 2.1 empty result res = getUserTranIdsFromRepoName("nosuchreponame") self.assertEqual(0, len(res)) #-- 2.2 has result res = getUserTranIdsFromRepoName("MMRPE420BS") self.assertEqual(2, len(res)) self.assertEqual('300734', res[0]) self.assertEqual('300735', res[1]) #-- 2.2 has result res = getUserTranIdsFromRepoName("MMRPE420BSS") self.assertEqual(1, len(res)) self.assertEqual('300736', res[0])
def testCancelRepoTransaction(self): #-- 1. create repo_master, repo_transaction and cancel the transaction normally master = self._get_test_repo_master() addRepoMaster(master) transaction = self._get_test_transaction() addRepoTransaction(transaction) cancel_transaction = {"UserTranId1": "300734"} self.assertEqual(cancelRepoTransaction(cancel_transaction), 0) session = sessionmaker(bind=DBConn.get_db(self.unittest_dbmode))() transaction_result = session.query(RepoTransaction) \ .filter_by(transaction_id=cancel_transaction['UserTranId1']) \ .first() self.assertEqual(Constants.REPO_TRANS_STATUS_CANCEL, transaction_result.status) session.close() #-- 2. cancel the transaction again. Unlike close or rerate, it will work normally #-- without throwing CloseCanceledRepoTransactionError self.assertEqual(cancelRepoTransaction(cancel_transaction), 0) #-- 3. cancel an unknown transaction to confirm RepoTransactionNotExistError will throw unknown_transaction = {"UserTranId1": "300734x"} with self.assertRaises(RepoTransactionNotExistError): cancelRepoTransaction(unknown_transaction)
def testAddRepoTransaction(self): master = self._get_test_repo_master() addRepoMaster(master) #-- 1. this invalid transaction shall raise input validation error (valueError) #-- 1.1. incorrect EventDate transaction = self._get_test_transaction() transaction["EventDate"] = "2018-08-32" with self.assertRaises(ValueError): addRepoTransaction(transaction) #-- 1.2. incorrect SettleDate transaction = self._get_test_transaction() transaction["SettleDate"] = "2018-08-32" with self.assertRaises(ValueError): addRepoTransaction(transaction) #-- 1.3. incorrect ActualSettleDate transaction = self._get_test_transaction() transaction["ActualSettleDate"] = "2018-08-32 00:00:00" with self.assertRaises(ValueError): addRepoTransaction(transaction) #-- 1.4. incorrect ActualSettleDate with non CALC value transaction = self._get_test_transaction() transaction["ActualSettleDate"] = "CALCC" with self.assertRaises(ValueError): addRepoTransaction(transaction) #-- 1.5. incorrect Investment transaction = self._get_test_transaction() transaction["Investment"] = "ISIN=" with self.assertRaises(ValueError): addRepoTransaction(transaction) #-- 1.6. incorrect Investment 2 transaction = self._get_test_transaction() transaction["Investment"] = "=XS1234567890" with self.assertRaises(ValueError): addRepoTransaction(transaction) #-- 1.7. incorrect Investment 3 transaction = self._get_test_transaction() transaction["Investment"] = "XS1234567890" with self.assertRaises(ValueError): addRepoTransaction(transaction) #-- 1.8. incorrect transactionType transaction = self._get_test_transaction() transaction["TransactionType"] = "abc12345" with self.assertRaises(InvalidRepoTransactionTypeError): addRepoTransaction(transaction) #-- 1.9. incorrect OpenEnded transaction = self._get_test_transaction() transaction["OpenEnded"] = "" with self.assertRaises(ValueError): addRepoTransaction(transaction) #-- 2. good transactions #-- 2.1. good transaction 1 - no OpenEnded transaction = self._get_test_transaction() self.assertEqual(addRepoTransaction(transaction), 0) session = sessionmaker(bind=DBConn.get_db(self.unittest_dbmode))() transaction_result = session.query(RepoTransaction) \ .filter_by(transaction_id=transaction['UserTranId1']) \ .first() self.assertEqual(transaction['UserTranId1'], transaction_result.transaction_id) session.commit() #-- 2.2. good transaction 2 - Maturity Date will be "" #-- condition: is_open_repo is true, maturity_date is CALC transaction = self._get_test_transaction() transaction["UserTranId1"] = "test100002" transaction["OpenEnded"] = "CALC" transaction["ActualSettleDate"] = "CALC" self.assertEqual(addRepoTransaction(transaction), 0) transaction_result = session.query(RepoTransaction) \ .filter_by(transaction_id=transaction['UserTranId1']) \ .first() self.assertEqual("", transaction_result.maturity_date) session.commit() #-- 2.3. good transaction 3 - Maturity Date will be value of ActualSettleDate #-- condition: is_open_repo is true, maturity_date is not CALC transaction = self._get_test_transaction() transaction["UserTranId1"] = "test100003" transaction["OpenEnded"] = "CALC" self.assertEqual(addRepoTransaction(transaction), 0) transaction_result = session.query(RepoTransaction) \ .filter_by(transaction_id=transaction['UserTranId1']) \ .first() self.assertEqual("2020-03-10", transaction_result.maturity_date) session.commit() #-- 2.4. good transaction 4 - Maturity Date will be ERROR #-- condition: is_open_repo is false, maturity_date is CALC transaction = self._get_test_transaction() transaction["UserTranId1"] = "test100004" transaction["ActualSettleDate"] = "CALC" self.assertEqual(addRepoTransaction(transaction), 0) transaction_result = session.query(RepoTransaction) \ .filter_by(transaction_id=transaction['UserTranId1']) \ .first() self.assertEqual("ERROR", transaction_result.maturity_date) session.commit() #-- 2.5. good transaction 5 - Maturity Date will be value of ActualSettleDate #-- condition: is_open_repo is false, maturity_date is not CALC transaction = self._get_test_transaction() transaction["UserTranId1"] = "test100005" self.assertEqual(addRepoTransaction(transaction), 0) transaction_result = session.query(RepoTransaction) \ .filter_by(transaction_id=transaction['UserTranId1']) \ .first() self.assertEqual("2020-03-10", transaction_result.maturity_date) session.commit() #-- 2.6. good transaction 6 - Maturity Date will be value of ActualSettleDate transaction = self._get_test_transaction() transaction["UserTranId1"] = "test100006" transaction["Portfolio"] = "中文基金1" transaction["LocationAccount"] = "中國銀行" self.assertEqual(addRepoTransaction(transaction), 0) transaction_result = session.query(RepoTransaction) \ .filter_by(transaction_id=transaction['UserTranId1']) \ .first() self.assertEqual("中文基金1", transaction_result.portfolio) self.assertEqual("中國銀行", transaction_result.custodian) session.close() #-- 3. duplicated transaction - shall raise RepoMasterAlreadyExistError transaction = self._get_test_transaction() with self.assertRaises(RepoTransactionAlreadyExistError): addRepoTransaction(transaction)
def testGetRepo(self): #-- preprocess: add 2 repo master and 6 transaction master1 = self._get_test_repo_master() addRepoMaster(master1) master2 = { "Code": "MMRPE420BS-2", "BifurcationCurrency": "USD", "AccrualDaysPerMonth": "Actual", "AccrualDaysPerYear": "180" } addRepoMaster(master2) transaction1 = { "TransactionType": "ReverseRepo_InsertUpdate", "UserTranId1": "300734", "Portfolio": "12734", "LocationAccount": "BOCHK", "Investment": "Isin=XS1234567890", "EventDate": "2020-12-31T00:00:00", "SettleDate": "2020-12-31T00:00:00", "OpenEnded": "CALC", "ActualSettleDate": "CALC", "Quantity": "300000", "CounterInvestment": "USD", "Price": "95.23", "NetCounterAmount": "1818234", "RepoName": "MMRPE420BS", "Coupon": "0.95", "LoanAmount": "1818234", "Broker": "BNP-REPO" } addRepoTransaction(transaction1) transaction2 = { "TransactionType": "ReverseRepo_InsertUpdate", "UserTranId1": "300735", "Portfolio": "12734", "LocationAccount": "BOCHK", "Investment": "Isin=XS1234567890", "EventDate": "2020-12-31T00:00:00", "SettleDate": "2020-12-31T00:00:00", "OpenEnded": "CALC", "ActualSettleDate": "2020-03-08T00:00:00", "Quantity": "300000", "CounterInvestment": "USD", "Price": "95.23", "NetCounterAmount": "1818234", "RepoName": "MMRPE420BS", "Coupon": "0.95", "LoanAmount": "1818234", "Broker": "BOC-REPO" } addRepoTransaction(transaction2) transaction3 = { "TransactionType": "Repo_InsertUpdate", "UserTranId1": "300736", "Portfolio": "12736", "LocationAccount": "BOCHK", "Investment": "Isin=XS1234567890", "EventDate": "2020-12-31T00:00:00", "SettleDate": "2020-12-31T00:00:00", "ActualSettleDate": "CALC", "Quantity": "300000", "CounterInvestment": "USD", "Price": "95.23", "NetCounterAmount": "1818234", "RepoName": "MMRPE420BS-2", "Coupon": "0.95", "LoanAmount": "1818234", "Broker": "BNP-REPO" } addRepoTransaction(transaction3) transaction4 = { "TransactionType": "Repo_InsertUpdate", "UserTranId1": "300737", "Portfolio": "中文", "LocationAccount": "中國銀行", "Investment": "Isin=XS1234567890", "EventDate": "2020-12-31T00:00:00", "SettleDate": "2020-12-31T00:00:00", "ActualSettleDate": "2020-03-08T00:00:00", "Quantity": "300000", "CounterInvestment": "USD", "Price": "95.23", "NetCounterAmount": "1818234", "RepoName": "MMRPE420BS-2", "Coupon": "0.95", "LoanAmount": "1818234", "Broker": "BOC-REPO" } addRepoTransaction(transaction4) transaction5 = { "TransactionType": "Repo_InsertUpdate", "UserTranId1": "300738", "Portfolio": "12734", "LocationAccount": "BOCHK", "Investment": "Isin=XS1234567890", "EventDate": "2020-12-31T00:00:00", "SettleDate": "2020-12-31T00:00:00", "ActualSettleDate": "2020-03-10T00:00:00", "Quantity": "300000", "CounterInvestment": "USD", "Price": "95.23", "NetCounterAmount": "1818234", "RepoName": "MMRPE420BS-2", "Coupon": "0.95", "LoanAmount": "1818234", "Broker": "BOC-REPO" } addRepoTransaction(transaction5) #-- preprocess: create 1 canceled and 1 closed transaction cancel_transaction = {"UserTranId1": "300738"} cancelRepoTransaction(cancel_transaction) transaction6 = { "TransactionType": "Repo_InsertUpdate", "UserTranId1": "300739", "Portfolio": "12734", "LocationAccount": "BOCHK", "Investment": "Isin=XS1234567890", "EventDate": "2020-12-31T00:00:00", "SettleDate": "2020-12-31T00:00:00", "ActualSettleDate": "2020-03-10T00:00:00", "Quantity": "300000", "CounterInvestment": "USD", "Price": "95.23", "NetCounterAmount": "1818234", "RepoName": "MMRPE420BS-2", "Coupon": "0.95", "LoanAmount": "1818234", "Broker": "BOC-REPO" } addRepoTransaction(transaction6) close_transaction = { "UserTranId1": "300739", "ActualSettleDate": "2018-08-31T00:00:00" } closeRepoTransaction(close_transaction) #-- 1. invalid value #-- 1.1 wrong status with self.assertRaises(ValueError): getRepo(status='open', portfolio='all', custodian='all', repoName='all', broker='all', hasHairCut='all') #-- 1.2 wrong hasHairCut with self.assertRaises(ValueError): getRepo(hasHairCut='0') #-- 2. normal query status #-- 2.1 status: openclose res = getRepo() with DBConn.get_db(self.unittest_dbmode).connect() as con: count = con.execute(""" SELECT count(transaction_id) FROM repo_transactions where (status='open' or status='closed') """).scalar() con.close() self.assertEqual(count, len(res)) #-- 2.2 status: all parameters inputted with default value res = getRepo(status='openclose', portfolio='all', custodian='all', repoName='all', broker='all', hasHairCut='all') with DBConn.get_db(self.unittest_dbmode).connect() as con: count = con.execute(""" SELECT count(transaction_id) FROM repo_transactions where (status='open' or status='closed') """).scalar() con.close() self.assertEqual(count, len(res)) #-- 2.3 status: cancel res = getRepo(status='canceled', portfolio='all', custodian='all', repoName='all', broker='all', hasHairCut='all') with DBConn.get_db(self.unittest_dbmode).connect() as con: count = con.execute(""" SELECT count(transaction_id) FROM repo_transactions where (status='canceled') """).scalar() con.close() #-- 2.4 status: all res = getRepo(status='all') with DBConn.get_db(self.unittest_dbmode).connect() as con: count = con.execute(""" SELECT count(transaction_id) FROM repo_transactions """).scalar() con.close() self.assertEqual(count, len(res)) #-- 3. normal query portfolio #-- 3.1 porfolio: english res = getRepo(portfolio='12734') with DBConn.get_db(self.unittest_dbmode).connect() as con: count = con.execute(""" SELECT count(transaction_id) FROM repo_transactions where (status='open' or status='closed') and portfolio='12734' """).scalar() con.close() self.assertEqual(count, len(res)) #-- 3.2 porfolio: 中文 res = getRepo(status='all', portfolio='中文') self.assertEqual(1, len(res)) #-- 4. normal query portfolio #-- 4.1 custodian: 中國銀行 res = getRepo(status='all', custodian='中國銀行') self.assertEqual(1, len(res)) #-- 4.2 custodian: english res = getRepo(custodian='BOCHK') self.assertEqual(4, len(res)) #-- 4. normal query repoName #-- 5.1 repoName: normal value (search status default input 'open') res = getRepo(repoName='MMRPE420BS-2') self.assertEqual(3, len(res)) #-- 5.2 repoName: empty result res = getRepo(repoName='--10--') self.assertEqual(0, len(res)) #-- 6. normal query repoName #-- 6.1 repoName: normal value res = getRepo(broker='BOC-REPO') self.assertEqual(3, len(res)) #-- 6.2 repoName: normal and status cancel res = getRepo(status='openclose', broker='BOC-REPO') with DBConn.get_db(self.unittest_dbmode).connect() as con: count = con.execute(""" SELECT count(transaction_id) FROM repo_transactions where (status='open' or status='closed') and broker='BOC-REPO' """).scalar() con.close() self.assertEqual(count, len(res)) #-- 6.3 repoName: empty result res = getRepo(broker='--REPO--') self.assertEqual(0, len(res)) #-- 7. normal query repoName #-- 7.1 hasHairCut: true res = getRepo(hasHairCut='True') self.assertEqual(0, len(res)) #-- 7.2 hasHairCut: false and status close res = getRepo(status='openclose', hasHairCut='False') with DBConn.get_db(self.unittest_dbmode).connect() as con: count = con.execute(""" SELECT count(transaction_id) FROM repo_transactions where (status='open' or status='closed') and haircut = 0 """).scalar() con.close() self.assertEqual(count, len(res))