ENH: Allow override of order amount rounding. (#1722)

* ENH: Use regular rounding to calculate order amounts.

We previously tried to prevent accidental over-ordering by truncating
orders down unless they were within 1e-4 of the next higher integer.
Unfortunately, this makes it easy for a sell order to be one share short
of the desired position.

Using regular rounding treats both buys and sells in the same way.

* ENH keep non-rounding behavior consistent, but leave code structured to make easier to override

* DOC make round_order public and describe behavior in docstring
This commit is contained in:
Jean Bredeche
2017-03-27 20:44:12 -04:00
committed by Paul Sutherland
parent 39188b393c
commit 6cf81a3f1c
2 changed files with 35 additions and 5 deletions
+21
View File
@@ -907,6 +907,27 @@ def before_trading_start(context, data):
)
self.assertEqual(algo.sim_params.data_frequency, 'minute')
def test_order_rounding(self):
answer_key = [
(0, 0),
(10, 10),
(1.1, 1),
(1.5, 1),
(1.9998, 1),
(1.99991, 2),
]
for input, answer in answer_key:
self.assertEqual(
answer,
TradingAlgorithm.round_order(input)
)
self.assertEqual(
-1 * answer,
TradingAlgorithm.round_order(-1 * input)
)
@parameterized.expand([
('order', TestOrderAlgorithm,),
('order_value', TestOrderValueAlgorithm,),
+14 -5
View File
@@ -131,7 +131,7 @@ from zipline.utils.events import (
from zipline.utils.factory import create_simulation_parameters
from zipline.utils.math_utils import (
tolerant_equals,
round_if_near_integer
round_if_near_integer,
)
from zipline.utils.pandas_utils import clear_dataframe_indexer_caches
from zipline.utils.preprocess import preprocess
@@ -1422,10 +1422,7 @@ class TradingAlgorithm(object):
def _calculate_order(self, asset, amount,
limit_price=None, stop_price=None, style=None):
# Truncate to the integer share count that's either within .0001 of
# amount or closer to zero.
# E.g. 3.9999 -> 4.0; 5.5 -> 5.0; -5.5 -> -5.0
amount = int(round_if_near_integer(amount))
amount = self.round_order(amount)
# Raises a ZiplineError if invalid parameters are detected.
self.validate_order_params(asset,
@@ -1441,6 +1438,18 @@ class TradingAlgorithm(object):
style)
return amount, style
@staticmethod
def round_order(amount):
"""
Convert number of shares to an integer.
By default, truncates to the integer share count that's either within
.0001 of amount or closer to zero.
E.g. 3.9999 -> 4.0; 5.5 -> 5.0; -5.5 -> -5.0
"""
return int(round_if_near_integer(amount))
def validate_order_params(self,
asset,
amount,