def test_stock_price_earnings_ratio(self): """ Tests correct price-earnings calculation for both `common` and `preferred` stock types. """ # Make a mock object for testing. sALE = Stock('ALE', 'common', 23, nan, 60) # Add some mock Trades. sALE.buy(500, 25) sALE.sell(300, 15) self.assertEqual(len(sALE._trades), 2) # Make a mock object for testing. sGIN = Stock('GIN', 'preferred', 8, 0.02, 100) # Add some mock Trades. sGIN.buy(320, 95) sGIN.sell(180, 110) self.assertEqual(len(sGIN._trades), 2) # `ALE` stock should use the last_dividend as dividend self.assertEqual(sALE.price_earnings_ratio(), ((500*25+300*15)/(500+300)) / 23.) # But `GIN` stock should the fixed_dividend * par_value as dividend self.assertEqual(sGIN.price_earnings_ratio(), ((320*95+180*110)/(320+180)) / (0.02 * 100))
def test_stock_dividend_yield_preferred(self): """ Tests correct dividend yield calculation for `preferred` stock types. """ # Make a mock object for testing. sGIN = Stock('GIN', 'preferred', 8, 0.02, 100) # A stock without trades has a default ticker price equal to its par # value. In this case, `preferred` stock types should have a price # earnings ratio equal to their par value. self.assertEqual(sGIN.dividend_yield(), 0.02) # Add some mock Trades. sGIN.buy(320, 95) sGIN.sell(180, 110) self.assertEqual(len(sGIN._trades), 2) # `preferred` stocks should not use the `common` calculation for # dividend yields... self.assertNotEqual(sGIN.dividend_yield(), 8 / ((320*95 + 180*110) / (320+180))) # ... instead, they should use the `preferred` calculation. self.assertEqual(sGIN.dividend_yield(), (0.02 * 100) / ((320*95 + 180*110) / (320+180)))
def test_stock_price_no_recent(self): """ Tests stock (ticker) price calculation for the case with no recent trades. """ # Make a mock object for testing. sALE = Stock('ALE', 'common', 23, nan, 60) # A stock without trades has a ticker price equal to its par value. self.assertEqual(sALE.stock_price(), 60) # Add some mock Trades between -30 and -15 minutes relative to now. sALE.buy(500, 25, datetime.datetime.now() - datetime.timedelta(minutes=16)) sALE.sell(300, 15, datetime.datetime.now() - datetime.timedelta(minutes=22)) self.assertEqual(len(sALE._trades), 2) # Now add some mock Trades prior to 30 minutes in the past. sALE.buy(250, 33, datetime.datetime.now() - datetime.timedelta(minutes=35)) sALE.sell(125, 55, datetime.datetime.now() - datetime.timedelta(minutes=39)) self.assertEqual(len(sALE._trades), 4) # Since the latest trade happened at -16 minutes relative to now, the # time window in which to calculate the stock price is [-29, -14]. self.assertEqual(sALE.stock_price(), ((500*25 + 300*15) / (500+300)))
def test_stock_dividend_yield_common(self): """ Tests correct dividend yield calculation for `common` stock types. """ # Make a mock object for testing. sALE = Stock('ALE', 'common', 23, nan, 60) # A stock without trades has a default ticker price equal to its par # value. self.assertEqual(sALE.dividend_yield(), 23. / 60) # Add some mock Trades. sALE.buy(500, 25) sALE.sell(300, 15) self.assertEqual(len(sALE._trades), 2) # The dividend yield calculation should now use a ticker price # determined from the average trading price. self.assertEqual(sALE.dividend_yield(), 23. / (((500*25)+(300*15))/(500+300)))
def test_stock_price(self): """ Tests stock (ticker) price calculation. """ # Make a mock object for testing. sALE = Stock('ALE', 'common', 23, nan, 60) # A stock without trades has a ticker price equal to its par value. self.assertEqual(sALE.stock_price(), 60) # Add some mock Trades. sALE.buy(500, 25) sALE.sell(300, 15) self.assertEqual(len(sALE._trades), 2) # Easy case for ticker price with two Trades. self.assertEqual(sALE.stock_price(), ((500*25)+(300*15))/(500+300)) # Add some mock Trades in the distant past (such that they are excluded # from the average). sALE.buy(100, 87, datetime.datetime.now() - datetime.timedelta(minutes=16)) sALE.buy(23, 34, datetime.datetime.now() - datetime.timedelta(minutes=15)) self.assertEqual(len(sALE._trades), 4) # Stock price should be unchanged. self.assertEqual(sALE.stock_price(), ((500*25)+(300*15))/(500+300))
def test_stock_buy_sell(self): """ Test buying and selling stocks. """ # Make a mock object for testing. # NOTE there are better ways to do this! sALE = Stock('ALE', 'common', 23, nan, 60) # Trade price should not be a string. with self.assertRaises(AssertionError): sALE.buy(500, 55, '2017 06 05 13 42 00') # Trade price should not be negative. with self.assertRaises(AssertionError): sALE.buy(500, -23) # Trade price should not be a float. with self.assertRaises(AssertionError): sALE.buy(500, 123.0) # Trade price should not be a string. with self.assertRaises(AssertionError): sALE.sell(500, 55, '2017 06 05 13 42 00') # Trade price should not be negative. with self.assertRaises(AssertionError): sALE.sell(500, -23) # Trade price should not be a float. with self.assertRaises(AssertionError): sALE.sell(500, 123.0) # `Buy` records should have a `+1` number in the buy_sell tuple record. sALE.buy(500, 25) self.assertEqual(sALE._trades[-1].buy_sell, 1) # `Sell` records should have a `-1` number in the buy_sell tuple record. sALE.sell(300, 15) self.assertEqual(sALE._trades[-1].buy_sell, -1) # Trading cannot happen in the future. with self.assertRaises(AssertionError): sALE.buy(500, 25, datetime.datetime.now() + datetime.timedelta(minutes=1))