diff --git a/tests/test_finance.py b/tests/test_finance.py index efe401e6..6ee06847 100644 --- a/tests/test_finance.py +++ b/tests/test_finance.py @@ -422,6 +422,7 @@ class FinanceTestCase(TestCase): self.assertEqual(1, aapl_order['sid']) # make sure the fls order did change - self.assertEqual(33, fls_order['amount']) - self.assertEqual(30, fls_order['limit']) + # to 300 shares at 3.33 + self.assertEqual(300, fls_order['amount']) + self.assertEqual(3.33, fls_order['limit']) self.assertEqual(2, fls_order['sid']) diff --git a/tests/test_perf_tracking.py b/tests/test_perf_tracking.py index 7cf27e49..192f16eb 100644 --- a/tests/test_perf_tracking.py +++ b/tests/test_perf_tracking.py @@ -110,7 +110,9 @@ class TestSplitPerformance(unittest.TestCase): # set up a long position in sid 1 # 100 shares at $20 apiece = $2000 position events.insert(0, create_txn(events[0], 20, 100)) - events.append(factory.create_split(1, 0.33333, + + # set up a split with ratio 3 + events.append(factory.create_split(1, 3, env.next_trading_day(events[1].dt))) results = calculate_results(self, events) diff --git a/zipline/finance/blotter.py b/zipline/finance/blotter.py index 5460f830..8a32592a 100644 --- a/zipline/finance/blotter.py +++ b/zipline/finance/blotter.py @@ -255,16 +255,16 @@ class Order(object): # info here: http://finra.complinet.com/en/display/display_plain.html? # rbid=2403&element_id=8950&record_id=12208&print=1 - # if we have an open order for 100 shares at $20, and we get - # a 3:1 split, we now want to have an open order for 33 shares at $60 - # for the amount, we round down to the nearest whole share - self.amount = int(self.amount * ratio) + # new_share_amount = old_share_amount / ratio + # new_price = old_price * ratio + + self.amount = int(self.amount / ratio) if self.limit: - self.limit = round(self.limit / ratio, 2) + self.limit = round(self.limit * ratio, 2) if self.stop: - self.stop = round(self.stop / ratio, 2) + self.stop = round(self.stop * ratio, 2) @property def open(self): diff --git a/zipline/finance/performance.py b/zipline/finance/performance.py index 93f0de03..1026d1d1 100644 --- a/zipline/finance/performance.py +++ b/zipline/finance/performance.py @@ -518,12 +518,18 @@ class Position(object): ratio = split.ratio + log.info("handling split for sid = " + str(split.sid) + + ", ratio = " + str(split.ratio)) + log.info("before split: " + str(self)) + # adjust the # of shares by the ratio - # (if we had 100 shares, and the ratio is 0.33333, + # (if we had 100 shares, and the ratio is 3, # we now have 33 shares) + # (old_share_count / ratio = new_share_count) + # (old_price * ratio = new_price) # ie, 33.333 - raw_share_count = self.amount * ratio + raw_share_count = self.amount / float(ratio) # ie, 33 full_share_count = math.floor(raw_share_count) @@ -532,18 +538,23 @@ class Position(object): fractional_share_count = raw_share_count - full_share_count # adjust the cost basis to the nearest cent, ie, 60.0 - new_cost_basis = round(self.cost_basis / ratio, 2) + new_cost_basis = round(self.cost_basis * ratio, 2) # adjust the last sale price - new_last_sale_price = round(self.last_sale_price / ratio, 2) + new_last_sale_price = round(self.last_sale_price * ratio, 2) self.cost_basis = new_cost_basis self.last_sale_price = new_last_sale_price self.amount = full_share_count + return_cash = round(float(fractional_share_count * new_cost_basis), 2) + + log.info("after split: " + str(self)) + log.info("returning cash: " + str(return_cash)) + # return the leftover cash, which will be converted into cash # (rounded to the nearest cent) - return round(float(fractional_share_count * new_cost_basis), 2) + return return_cash def update(self, txn): if(self.sid != txn.sid): @@ -663,12 +674,13 @@ class PerformancePeriod(object): self.positions[div.sid].add_dividend(div) def handle_split(self, split): - # Make the position object handle the split. It returns the - # leftover cash from a fractional share, if there is any. - leftover_cash = self.positions[split.sid].handle_split(split) + if split.sid in self.positions: + # Make the position object handle the split. It returns the + # leftover cash from a fractional share, if there is any. + leftover_cash = self.positions[split.sid].handle_split(split) - if leftover_cash > 0: - self.handle_cash_payment(leftover_cash) + if leftover_cash > 0: + self.handle_cash_payment(leftover_cash) def update_dividends(self, todays_date): """