Merge pull request #207 from quantopian/splits_fixes

fixing some bugs with splits (ratios and empty positions)
This commit is contained in:
jbredeche
2013-07-25 09:28:38 -07:00
4 changed files with 34 additions and 19 deletions
+3 -2
View File
@@ -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'])
+3 -1
View File
@@ -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)
+6 -6
View File
@@ -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):
+22 -10
View File
@@ -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):
"""