mirror of
https://github.com/wassname/catalyst.git
synced 2026-07-09 09:18:00 +08:00
ENH: Add style parameters to order API helper methods.
Add `style` parameter to order_value, order_percent, order_target, order_target_percent, and order_target_value methods. The style parameter is forwarded to the underlying call to `order`.
This commit is contained in:
@@ -26,6 +26,7 @@ import zipline.utils.simfactory as simfactory
|
||||
from zipline.test_algorithms import (TestRegisterTransformAlgorithm,
|
||||
RecordAlgorithm,
|
||||
TestOrderAlgorithm,
|
||||
TestOrderStyleForwardingAlgorithm,
|
||||
TestOrderInstantAlgorithm,
|
||||
TestOrderValueAlgorithm,
|
||||
TestTargetAlgorithm,
|
||||
@@ -211,6 +212,24 @@ class TestTransformAlgorithm(TestCase):
|
||||
)
|
||||
algo.run(self.df)
|
||||
|
||||
def test_order_method_style_forwarding(self):
|
||||
|
||||
method_names_to_test = ['order',
|
||||
'order_value',
|
||||
'order_percent',
|
||||
'order_target',
|
||||
'order_target_percent',
|
||||
'order_target_value']
|
||||
|
||||
for name in method_names_to_test:
|
||||
algo = TestOrderStyleForwardingAlgorithm(
|
||||
sim_params=self.sim_params,
|
||||
data_frequency='daily',
|
||||
instant_fill=False,
|
||||
method_name=name
|
||||
)
|
||||
algo.run(self.df)
|
||||
|
||||
def test_order_instant(self):
|
||||
algo = TestOrderInstantAlgorithm(sim_params=self.sim_params,
|
||||
data_frequency='daily',
|
||||
|
||||
+38
-14
@@ -537,7 +537,8 @@ class TradingAlgorithm(object):
|
||||
return MarketOrder()
|
||||
|
||||
@api_method
|
||||
def order_value(self, sid, value, limit_price=None, stop_price=None):
|
||||
def order_value(self, sid, value,
|
||||
limit_price=None, stop_price=None, style=None):
|
||||
"""
|
||||
Place an order by desired value rather than desired number of shares.
|
||||
If the requested sid is found in the universe, the requested value is
|
||||
@@ -561,7 +562,10 @@ class TradingAlgorithm(object):
|
||||
return
|
||||
else:
|
||||
amount = value / last_price
|
||||
return self.order(sid, amount, limit_price, stop_price)
|
||||
return self.order(sid, amount,
|
||||
limit_price=limit_price,
|
||||
stop_price=stop_price,
|
||||
style=style)
|
||||
|
||||
@property
|
||||
def recorded_vars(self):
|
||||
@@ -639,7 +643,8 @@ class TradingAlgorithm(object):
|
||||
self.annualizer = ANNUALIZER[self.data_frequency]
|
||||
|
||||
@api_method
|
||||
def order_percent(self, sid, percent, limit_price=None, stop_price=None):
|
||||
def order_percent(self, sid, percent,
|
||||
limit_price=None, stop_price=None, style=None):
|
||||
"""
|
||||
Place an order in the specified security corresponding to the given
|
||||
percent of the current portfolio value.
|
||||
@@ -647,10 +652,14 @@ class TradingAlgorithm(object):
|
||||
Note that percent must expressed as a decimal (0.50 means 50\%).
|
||||
"""
|
||||
value = self.portfolio.portfolio_value * percent
|
||||
return self.order_value(sid, value, limit_price, stop_price)
|
||||
return self.order_value(sid, value,
|
||||
limit_price=limit_price,
|
||||
stop_price=stop_price,
|
||||
style=style)
|
||||
|
||||
@api_method
|
||||
def order_target(self, sid, target, limit_price=None, stop_price=None):
|
||||
def order_target(self, sid, target,
|
||||
limit_price=None, stop_price=None, style=None):
|
||||
"""
|
||||
Place an order to adjust a position to a target number of shares. If
|
||||
the position doesn't already exist, this is equivalent to placing a new
|
||||
@@ -661,13 +670,19 @@ class TradingAlgorithm(object):
|
||||
if sid in self.portfolio.positions:
|
||||
current_position = self.portfolio.positions[sid].amount
|
||||
req_shares = target - current_position
|
||||
return self.order(sid, req_shares, limit_price, stop_price)
|
||||
return self.order(sid, req_shares,
|
||||
limit_price=limit_price,
|
||||
stop_price=stop_price,
|
||||
style=style)
|
||||
else:
|
||||
return self.order(sid, target, limit_price, stop_price)
|
||||
return self.order(sid, target,
|
||||
limit_price=limit_price,
|
||||
stop_price=stop_price,
|
||||
style=style)
|
||||
|
||||
@api_method
|
||||
def order_target_value(self, sid, target, limit_price=None,
|
||||
stop_price=None):
|
||||
def order_target_value(self, sid, target,
|
||||
limit_price=None, stop_price=None, style=None):
|
||||
"""
|
||||
Place an order to adjust a position to a target value. If
|
||||
the position doesn't already exist, this is equivalent to placing a new
|
||||
@@ -680,13 +695,19 @@ class TradingAlgorithm(object):
|
||||
current_price = self.trading_client.current_data[sid].price
|
||||
current_value = current_position * current_price
|
||||
req_value = target - current_value
|
||||
return self.order_value(sid, req_value, limit_price, stop_price)
|
||||
return self.order_value(sid, req_value,
|
||||
limit_price=limit_price,
|
||||
stop_price=stop_price,
|
||||
style=style)
|
||||
else:
|
||||
return self.order_value(sid, target, limit_price, stop_price)
|
||||
return self.order_value(sid, target,
|
||||
limit_price=limit_price,
|
||||
stop_price=stop_price,
|
||||
style=style)
|
||||
|
||||
@api_method
|
||||
def order_target_percent(self, sid, target, limit_price=None,
|
||||
stop_price=None):
|
||||
def order_target_percent(self, sid, target,
|
||||
limit_price=None, stop_price=None, style=None):
|
||||
"""
|
||||
Place an order to adjust a position to a target percent of the
|
||||
current portfolio value. If the position doesn't already exist, this is
|
||||
@@ -705,7 +726,10 @@ class TradingAlgorithm(object):
|
||||
target_value = self.portfolio.portfolio_value * target
|
||||
|
||||
req_value = target_value - current_value
|
||||
return self.order_value(sid, req_value, limit_price, stop_price)
|
||||
return self.order_value(sid, req_value,
|
||||
limit_price=limit_price,
|
||||
stop_price=stop_price,
|
||||
style=style)
|
||||
|
||||
@api_method
|
||||
def get_open_orders(self, sid=None):
|
||||
|
||||
@@ -79,6 +79,7 @@ from six import itervalues
|
||||
|
||||
from zipline.algorithm import TradingAlgorithm
|
||||
from zipline.api import FixedSlippage
|
||||
from zipline.finance.execution import StopLimitOrder
|
||||
|
||||
|
||||
class TestAlgorithm(TradingAlgorithm):
|
||||
@@ -261,6 +262,37 @@ class TestOrderInstantAlgorithm(TradingAlgorithm):
|
||||
self.last_price = data[0].price
|
||||
|
||||
|
||||
class TestOrderStyleForwardingAlgorithm(TradingAlgorithm):
|
||||
"""
|
||||
Test Algorithm for verifying that ExecutionStyles are properly forwarded by
|
||||
order API helper methods. Pass the name of the method to be tested as a
|
||||
string parameter to this algorithm's constructor.
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.method_name = kwargs.pop('method_name')
|
||||
super(TestOrderStyleForwardingAlgorithm, self)\
|
||||
.__init__(*args, **kwargs)
|
||||
|
||||
def initialize(self):
|
||||
self.incr = 0
|
||||
self.last_price = None
|
||||
|
||||
def handle_data(self, data):
|
||||
if self.incr == 0:
|
||||
assert len(self.portfolio.positions.keys()) == 0
|
||||
|
||||
method_to_check = getattr(self, self.method_name)
|
||||
method_to_check(0, data[0].price, style=StopLimitOrder(10, 10))
|
||||
|
||||
assert len(self.blotter.open_orders[0]) == 1
|
||||
result = self.blotter.open_orders[0][0]
|
||||
assert result.limit == 10
|
||||
assert result.stop == 10
|
||||
|
||||
self.incr += 1
|
||||
|
||||
|
||||
class TestOrderValueAlgorithm(TradingAlgorithm):
|
||||
def initialize(self):
|
||||
self.incr = 0
|
||||
|
||||
Reference in New Issue
Block a user