From 30c995f76dd7b728942540c57f592eed349a599f Mon Sep 17 00:00:00 2001 From: Michael Halls-Moore Date: Mon, 2 Feb 2015 18:57:02 +0000 Subject: [PATCH] Added two extra unit tests to Portfolio --- portfolio/portfolio.py | 11 +-- portfolio/portfolio_test.py | 130 ++++++++++++++++++++++++++++++++++-- portfolio/position.py | 2 +- 3 files changed, 131 insertions(+), 12 deletions(-) diff --git a/portfolio/portfolio.py b/portfolio/portfolio.py index f279ff6..8036003 100644 --- a/portfolio/portfolio.py +++ b/portfolio/portfolio.py @@ -54,9 +54,10 @@ class Portfolio(object): else: ps = self.positions[market] ps.units -= units - ps.exposure -= float(units) - ps.update_position_price(self, remove_price) - pnl = ps.profit_base + exposure = float(units) + ps.exposure -= exposure + ps.update_position_price(remove_price) + pnl = ps.calculate_pips() * exposure / remove_price self.balance += pnl return True @@ -67,8 +68,8 @@ class Portfolio(object): return False else: ps = self.positions[market] - ps.update_position_price(self, remove_price) - pnl = ps.profit_base + ps.update_position_price(remove_price) + pnl = ps.calculate_pips() * ps.exposure / remove_price self.balance += pnl del[self.positions[market]] return True diff --git a/portfolio/portfolio_test.py b/portfolio/portfolio_test.py index f06e5da..d8eabfe 100644 --- a/portfolio/portfolio_test.py +++ b/portfolio/portfolio_test.py @@ -41,8 +41,8 @@ class TestPortfolio(unittest.TestCase): side = "LONG" units = 2000 exposure = float(units) - add_price = 1.51928 - remove_price = 1.51878 + add_price = 1.51819 + remove_price = 1.51770 # Test for no position market = "EUR/USD" @@ -52,17 +52,135 @@ class TestPortfolio(unittest.TestCase): ) self.assertFalse(apu) - # Test for real position - market = "GBP/USD" + # Add a position and test for real position + market = "GBP/USD" + self.port.add_new_position( + side, market, units, exposure, + add_price, remove_price + ) + ps = self.port.positions[market] + + # Test for addition of units + add_price = 1.51928 + remove_price = 1.51878 apu = self.port.add_position_units( market, units, exposure, add_price, remove_price ) self.assertTrue(apu) - ps = self.port.positions[market] - self.assertAlmostEqual(ps.avg_price, 1.518735) + def test_remove_position_units(self): + side = "LONG" + units = 2000 + exposure = float(units) + add_price = 1.51819 + remove_price = 1.51770 + + # Test for no position + market = "EUR/USD" + apu = self.port.remove_position_units( + market, units, remove_price + ) + self.assertFalse(apu) + + # Add a position and then add units to it + market = "GBP/USD" + self.port.add_new_position( + side, market, units, exposure, + add_price, remove_price + ) + ps = self.port.positions[market] + add_price = 1.51928 + remove_price = 1.51878 + add_units = 8000 + add_exposure = float(add_units) + apu = self.port.add_position_units( + market, add_units, add_exposure, + add_price, remove_price + ) + self.assertEqual(ps.units, 10000) + self.assertEqual(ps.exposure, 10000.0) + self.assertAlmostEqual(ps.avg_price, 1.519062) + + # Test removal of (some) of the units + add_price = 1.52134 + remove_price = 1.52017 + remove_units = 3000 + rpu = self.port.remove_position_units( + market, remove_units, remove_price + ) + self.assertTrue(rpu) + self.assertEqual(ps.units, 7000) + self.assertEqual(ps.exposure, 7000.0) + self.assertAlmostEqual(ps.profit_base, 5.102060953709626) + self.assertAlmostEqual(self.port.balance, 100002.18659755158) + + def test_close_position(self): + side = "LONG" + units = 2000 + exposure = float(units) + add_price = 1.51819 + remove_price = 1.51770 + + # Test for no position + market = "EUR/USD" + cp = self.port.close_position( + market, remove_price + ) + self.assertFalse(cp) + + # Add a position and then close it + # Will lose money on the spread + market = "GBP/USD" + self.port.add_new_position( + side, market, units, exposure, + add_price, remove_price + ) + ps = self.port.positions[market] + cp = self.port.close_position( + market, remove_price + ) + self.assertTrue(cp) + self.assertRaises(ps) # Key doesn't exist + self.assertAlmostEqual(self.port.balance, 99999.35428609079) + + # Add 2000, add another 8000, remove 3000 and then + # close the position. Balance should be as expected + # for a multi-leg transaction. + self.port.add_new_position( + side, market, units, exposure, + add_price, remove_price + ) + ps = self.port.positions[market] + add_price = 1.51928 + remove_price = 1.51878 + add_units = 8000 + add_exposure = float(add_units) + apu = self.port.add_position_units( + market, add_units, add_exposure, + add_price, remove_price + ) + self.assertEqual(ps.units, 10000) + self.assertEqual(ps.exposure, 10000.0) + self.assertAlmostEqual(ps.avg_price, 1.519062) + add_price = 1.52134 + remove_price = 1.52017 + remove_units = 3000 + rpu = self.port.remove_position_units( + market, remove_units, remove_price + ) + self.assertEqual(ps.units, 7000) + self.assertEqual(ps.exposure, 7000.0) + self.assertAlmostEqual(ps.profit_base, 5.102060953709626) + self.assertAlmostEqual(self.port.balance, 100001.54088364237) + cp = self.port.close_position( + market, remove_price + ) + self.assertTrue(cp) + self.assertRaises(ps) # Key doesn't exist + self.assertAlmostEqual(self.port.balance, 100006.64294459608) + if __name__ == "__main__": unittest.main() \ No newline at end of file diff --git a/portfolio/position.py b/portfolio/position.py index 21728e9..ca50880 100644 --- a/portfolio/position.py +++ b/portfolio/position.py @@ -19,7 +19,7 @@ class Position(object): return mult * (self.cur_price - self.avg_price) def calculate_profit_base(self): - pips = self.calculate_pips() + pips = self.calculate_pips() return pips * self.exposure / self.cur_price def calculate_profit_perc(self):