mirror of
https://github.com/wassname/catalyst.git
synced 2026-07-06 02:45:53 +08:00
Merge pull request #220 from quantopian/minimum_price_variation
Merging branch "Minimum price variation" Ensure limit prices conform to a minimum price variation of a penny, which works for most stocks (not, for instance, BRK). The rounding "midpoint" is custom and depends on buy/sell direction, instead of .5 of a penny.
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
import math
|
||||
|
||||
from nose_parameterized import parameterized
|
||||
from unittest import TestCase
|
||||
|
||||
from zipline.finance.blotter import round_for_minimum_price_variation
|
||||
|
||||
|
||||
class BlotterTestCase(TestCase):
|
||||
|
||||
@parameterized.expand([(0.00, 0.00),
|
||||
(0.01, 0.01),
|
||||
(0.0005, 0.00),
|
||||
(1.006, 1.00),
|
||||
(1.0095, 1.01),
|
||||
(1.00949, 1.00),
|
||||
(1.0005, 1.00)])
|
||||
def test_round_for_minimum_price_variation_buy(self, price, expected):
|
||||
result = round_for_minimum_price_variation(price, is_buy=True)
|
||||
self.assertEqual(result, expected)
|
||||
self.assertEqual(math.copysign(1.0, result),
|
||||
math.copysign(1.0, expected))
|
||||
|
||||
@parameterized.expand([(0.00, 0.00),
|
||||
(0.01, 0.01),
|
||||
(0.0005, 0.00),
|
||||
(1.006, 1.01),
|
||||
(1.0005, 1.00),
|
||||
(1.00051, 1.01),
|
||||
(1.0095, 1.01)])
|
||||
def test_round_for_minimum_price_variation_sell(self, price, expected):
|
||||
result = round_for_minimum_price_variation(price, is_buy=False)
|
||||
self.assertEqual(result, expected)
|
||||
self.assertEqual(math.copysign(1.0, result),
|
||||
math.copysign(1.0, expected))
|
||||
@@ -42,6 +42,17 @@ ORDER_STATUS = Enum(
|
||||
)
|
||||
|
||||
|
||||
# On an order to buy, between .05 below to .95 above a penny, use that penny.
|
||||
# On an order to sell, between .05 above to .95 below a penny, use that penny.
|
||||
# buy: [.0095, .0195) -> round to .01, sell: (.0005, .0105] -> round to .01
|
||||
def round_for_minimum_price_variation(x, is_buy, diff=(0.0095 - .005)):
|
||||
# relies on rounding half away from zero, unlike numpy's bankers' rounding
|
||||
rounded = round(x - (diff if is_buy else -diff), 2)
|
||||
if zp_math.tolerant_equals(rounded, 0.0):
|
||||
return 0.0
|
||||
return rounded
|
||||
|
||||
|
||||
class Blotter(object):
|
||||
|
||||
def __init__(self):
|
||||
@@ -107,6 +118,9 @@ class Blotter(object):
|
||||
raise OverflowError("Can't order more than %d shares" %
|
||||
self.max_shares)
|
||||
|
||||
if limit_price:
|
||||
limit_price = round_for_minimum_price_variation(limit_price,
|
||||
amount > 0)
|
||||
order = Order(
|
||||
dt=self.current_dt,
|
||||
sid=sid,
|
||||
|
||||
Reference in New Issue
Block a user