Pulled in PR 137 to add new order methods.

This commit is contained in:
Thomas Wiecki
2013-08-08 15:57:24 -04:00
5 changed files with 119 additions and 10 deletions
+21 -7
View File
@@ -21,7 +21,13 @@ from zipline.utils.test_utils import setup_logger
import zipline.utils.factory as factory
from zipline.test_algorithms import (TestRegisterTransformAlgorithm,
RecordAlgorithm,
TestOrderAlgorithm)
TestOrderAlgorithm,
TestOrderValueAlgorithm,
TestTargetAlgorithm,
TestOrderPercentAlgorithm,
TestTargetPercentAlgorithm,
TestTargetValueAlgorithm)
from zipline.sources import (SpecificEquityTrades,
DataFrameSource,
DataPanelSource)
@@ -166,9 +172,17 @@ class TestTransformAlgorithm(TestCase):
self.assertEqual(algo.data_frequency, 'minute')
self.assertEqual(algo.annualizer, 10)
def test_orders_executed(self):
algo = TestOrderAlgorithm(
sim_params=self.sim_params,
data_frequency='daily'
)
algo.run(self.df)
def test_order_methods(self):
AlgoClasses = [TestOrderAlgorithm,
TestOrderValueAlgorithm,
TestTargetAlgorithm,
TestOrderPercentAlgorithm,
TestTargetPercentAlgorithm,
TestTargetValueAlgorithm]
for AlgoClass in AlgoClasses:
algo = AlgoClass(
sim_params=self.sim_params,
data_frequency='daily'
)
algo.run(self.df)
+1 -1
View File
@@ -231,7 +231,7 @@ class TestBatchTransform(TestCase):
# consecutive (of window length) numbers up till the end.
for i in range(algo.window_length, len(test_history)):
np.testing.assert_array_equal(
range(i - algo.window_length + 1, i + 1),
range(i - algo.window_length + 2, i + 2d),
test_history[i].values.flatten()
)
+69
View File
@@ -366,6 +366,12 @@ class TradingAlgorithm(object):
def order(self, sid, amount, limit_price=None, stop_price=None):
return self.blotter.order(sid, amount, limit_price, stop_price)
def order_value(self, sid, value, limit_price=None, stop_price=None):
last_price = self.trading_client.current_data[sid].price
return self.blotter.order_value(sid, value, last_price,
limit_price=limit_price,
stop_price=stop_price)
@property
def recorded_vars(self):
return copy(self._recorded_vars)
@@ -430,3 +436,66 @@ class TradingAlgorithm(object):
assert data_frequency in ('daily', 'minute')
self.data_frequency = data_frequency
self.annualizer = ANNUALIZER[self.data_frequency]
def order_percent(self, sid, percent, limit_price=None, stop_price=None):
"""
Place an order in the specified security corresponding to the given
percent of the current portfolio value.
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)
def target(self, sid, target, limit_price=None, stop_price=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
order. If the position does exist, this is equivalent to placing an
order for the difference between the target number of shares and the
current number of shares.
"""
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)
else:
return self.order(sid, target, limit_price, stop_price)
def target_value(self, sid, target, limit_price=None, stop_price=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
order. If the position does exist, this is equivalent to placing an
order for the difference between the target value and the
current value.
"""
if sid in self.portfolio.positions:
current_position = self.portfolio.positions[sid].amount
current_price = self.portfolio.positions[sid].last_sale_price
current_value = current_position * current_price
req_value = target - current_value
return self.order_value(sid, req_value, limit_price, stop_price)
else:
return self.order_value(sid, target, limit_price, stop_price)
def target_percent(self, sid, target, limit_price=None, stop_price=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
equivalent to placing a new order. If the position does exist, this is
equivalent to placing an order for the difference between the target
percent and the current percent.
Note that target must expressed as a decimal (0.50 means 50\%).
"""
if sid in self.portfolio.positions:
current_position = self.portfolio.positions[sid].amount
current_price = self.portfolio.positions[sid].last_sale_price
current_value = current_position * current_price
else:
current_value = 0
target_value = self.portfolio.portfolio_value * target
req_value = target_value - current_value
return self.order_value(sid, req_value, limit_price, stop_price)
+27 -1
View File
@@ -18,6 +18,7 @@ import uuid
from copy import copy
from logbook import Logger
from collections import defaultdict
import numpy as np
import zipline.errors
import zipline.protocol as zp
@@ -93,7 +94,7 @@ class Blotter(object):
# just validates amount and passes rest on to TransactionSimulator
# Tell the user if they try to buy 0 shares of something.
if amount == 0:
if int(amount) == 0:
zero_message = "Requested to trade zero shares of {psid}".format(
psid=sid
)
@@ -124,6 +125,31 @@ class Blotter(object):
return order.id
def order_value(self, sid, value, last_price,
limit_price=None, stop_price=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
divided by its price to imply the number of shares to transact.
value > 0 :: Buy/Cover
value < 0 :: Sell/Short
Market order: order(sid, value)
Limit order: order(sid, value, limit_price)
Stop order: order(sid, value, None, stop_price)
StopLimit order: order(sid, value, limit_price, stop_price)
"""
if np.allclose(last_price, 0):
zero_message = "Price of 0 for {psid}; can't infer value".format(
psid=sid
)
log.debug(zero_message)
# Don't place any order
return
else:
amount = value / last_price
return self.order(sid, amount, limit_price, stop_price)
def cancel(self, order_id):
if order_id not in self.orders:
return
+1 -1
View File
@@ -326,7 +326,7 @@ def create_test_df_source(sim_params=None, bars='daily'):
if i >= market_open and i <= market_close:
new_index.append(i)
index = new_index
x = np.arange(0, len(index))
x = np.arange(1, len(index) + 1)
df = pd.DataFrame(x, index=index, columns=[0])