updated based on PR feedback.

This commit is contained in:
fawce
2012-09-30 22:12:00 -04:00
parent ebde40ab05
commit 7a8697f0e5
8 changed files with 80 additions and 47 deletions
-4
View File
@@ -303,10 +303,6 @@ class BatchTransformTestCase(TestCase):
# test overloaded class
for test_history in [algo.history_return_price_class, algo.history_return_price_decorator]:
self.assertTrue(np.all(test_history[2].values.flatten() == range(4, 10)))
self.assertTrue(np.all(test_history[3].values.flatten() == range(4, 10)))
self.assertTrue(np.all(test_history[4].values.flatten() == range(6, 14)))
np.testing.assert_array_equal(
range(4, 10),
test_history[2].values.flatten()
+3 -3
View File
@@ -5,7 +5,7 @@ from zipline.gens.tradegens import DataFrameSource
from zipline.utils.factory import create_trading_environment
from zipline.gens.transform import StatefulTransform
from zipline.lines import SimulatedTrading
from zipline.finance.slippage import FixedSlippage, simulate_method_factory
from zipline.finance.slippage import FixedSlippage, transact_partial
from zipline.finance.commission import PerShare
@@ -75,7 +75,7 @@ class TradingAlgorithm(object):
transforms,
self,
environment,
simulate_method_factory(FixedSlippage(), PerShare(0.0))
transact_partial(FixedSlippage(), PerShare(0.0))
)
def run(self, source, start=None, end=None):
@@ -180,5 +180,5 @@ class TradingAlgorithm(object):
def initialize(self, *args, **kwargs):
pass
def set_simulate_override(self, slippage_callable):
def set_transact_setter(self, transact_setter):
pass
+26
View File
@@ -1,18 +1,44 @@
class PerShare(object):
"""
Calculates a commission for a transaction based on a per
share cost.
"""
def __init__(self, cost=0.03):
"""
Cost parameter is the cost of a trade per-share. $0.03
means three cents per share, which is a very conservative
(quite high) for per share costs.
"""
self.cost = cost
def calculate(self, transaction):
"""
returns a tuple of:
(per share commission, total transaction commission)
"""
return self.cost, abs(transaction.amount * self.cost)
class PerTrade(object):
"""
Calculates a commission for a transaction based on a per
trade cost.
"""
def __init__(self, cost=5.0):
"""
Cost parameter is the cost of a trade, regardless of
share count. $5.00 per trade is fairly typical of
discount brokers.
"""
self.cost = cost
def calculate(self, transaction):
"""
returns a tuple of:
(per share commission, total transaction commission)
"""
if transaction.amount == 0:
return 0.0, 0.0
+15 -10
View File
@@ -1,20 +1,25 @@
import pytz
import math
from functools import partial
import zipline.protocol as zp
def transact_stub(slippage, commission, open_orders, events):
"""
This is intended to be wrapped in a partial, so that the
slippage and commission models can be enclosed.
"""
transaction = slippage.simulate(open_orders, events)
if transaction:
per_share, total_commission = commission.calculate(transaction)
transaction.price = transaction.price + per_share
transaction.commission = total_commission
return transaction
def simulate_method_factory(slippage, commission):
def simulate(open_orders, events):
transaction = slippage.simulate(open_orders, events)
if transaction:
per_share, total_commission = commission.calculate(transaction)
transaction.price = transaction.price + per_share
transaction.commission = total_commission
return transaction
return simulate
def transact_partial(slippage, commission):
return partial(transact_stub, slippage, commission)
def create_transaction(sid, amount, price, dt):
+6 -6
View File
@@ -7,7 +7,7 @@ from collections import defaultdict
import zipline.protocol as zp
from zipline.finance.slippage import (
VolumeShareSlippage,
simulate_method_factory
transact_partial
)
from zipline.finance.commission import PerShare
@@ -15,11 +15,11 @@ log = logbook.Logger('Transaction Simulator')
class TransactionSimulator(object):
def __init__(self, simulate=None):
if simulate:
self.simulate = simulate
def __init__(self, transact=None):
if transact != None:
self.transact = transact
else:
self.simulate = simulate_method_factory(
self.transact = transact_partial(
VolumeShareSlippage(),
PerShare()
)
@@ -43,7 +43,7 @@ class TransactionSimulator(object):
event.TRANSACTION = None
# We only fill transactions on trade events.
if event.type == zp.DATASOURCE_TYPE.TRADE:
event.TRANSACTION = self.simulate(event, self.open_orders)
event.TRANSACTION = self.transact(event, self.open_orders)
return event
+15 -9
View File
@@ -52,14 +52,14 @@ class TradeSimulationClient(object):
is sent to the algo.
"""
def __init__(self, algo, environment, txn_sim):
def __init__(self, algo, environment, transact):
self.algo = algo
self.sids = algo.get_sid_filter()
self.environment = environment
self.txn_sim = txn_sim
self.transact = transact
self.ordering_client = TransactionSimulator(self.txn_sim)
self.ordering_client = TransactionSimulator(self.transact)
self.perf_tracker = PerformanceTracker(self.environment, self.sids)
self.algo_start = self.environment.first_open
@@ -130,8 +130,10 @@ class AlgorithmSimulator(object):
self.algolog = Logger("AlgoLog")
self.algo.set_logger(self.algolog)
# Porived user algorithm with slippage override.
self.algo.set_simulate_override(self.simulate_override)
# Provide user algorithm with a setter for the transact
# method (method that constructs transactions based on
# open orders and trade events).
self.algo.set_transact_setter(self.set_transact)
# Handler for heartbeats during calls to handle_data.
def log_heartbeats(beat_count, stackframe):
@@ -173,13 +175,17 @@ class AlgorithmSimulator(object):
record.extra['algo_dt'] = self.snapshot_dt
self.processor = Processor(inject_algo_dt)
def simulate_override(self, slippage):
self.order_book.slippage = slippage
def set_transact(self, transact):
"""
Set the method that will be called to create a
transaction from open orders and trade events.
"""
self.order_book.transact = transact
def order(self, sid, amount):
"""
Closure to pass into the user's algo to allow placing orders
into the txn_sim's dict of open orders.
into the transaction simulator's dict of open orders.
"""
assert sid in self.sids, "Order on invalid sid: %i" % sid
order = ndict({
@@ -230,7 +236,7 @@ class AlgorithmSimulator(object):
if date == 'DONE':
for event in snapshot:
yield event.perf_message
raise StopIteration()
raise StopIteration
# We're still in the warmup period. Use the event to
# update our universe, but don't yield any perf messages,
+12 -12
View File
@@ -44,8 +44,8 @@ The algorithm must expose methods:
self.Portfolio[sid(133)]['cost_basis']
- set_simulate_override: method that accepts a callable. Will
be set as the value of the set_simulate_override method of
- set_transact_setter: method that accepts a callable. Will
be set as the value of the set_transact_setter method of
the trading_client. This allows an algorithm to change the
slippage model used to predict transactions based on orders
and trade events.
@@ -97,7 +97,7 @@ class TestAlgorithm():
def get_sid_filter(self):
return self.sid_filter
def set_simulate_override(self, txn_sim_callable):
def set_transact_setter(self, txn_sim_callable):
pass
@@ -138,7 +138,7 @@ class HeavyBuyAlgorithm():
def get_sid_filter(self):
return [self.sid]
def set_simulate_override(self, txn_sim_callable):
def set_transact_setter(self, txn_sim_callable):
pass
class NoopAlgorithm(object):
@@ -164,7 +164,7 @@ class NoopAlgorithm(object):
def get_sid_filter(self):
return []
def set_simulate_override(self, txn_sim_callable):
def set_transact_setter(self, txn_sim_callable):
pass
class ExceptionAlgorithm(object):
@@ -210,7 +210,7 @@ class ExceptionAlgorithm(object):
else:
return [self.sid]
def set_simulate_override(self, txn_sim_callable):
def set_transact_setter(self, txn_sim_callable):
pass
class DivByZeroAlgorithm():
@@ -240,7 +240,7 @@ class DivByZeroAlgorithm():
def get_sid_filter(self):
return [self.sid]
def set_simulate_override(self, txn_sim_callable):
def set_transact_setter(self, txn_sim_callable):
pass
class InitializeTimeoutAlgorithm():
@@ -269,7 +269,7 @@ class InitializeTimeoutAlgorithm():
def get_sid_filter(self):
return [self.sid]
def set_simulate_override(self, txn_sim_callable):
def set_transact_setter(self, txn_sim_callable):
pass
class TooMuchProcessingAlgorithm():
@@ -297,7 +297,7 @@ class TooMuchProcessingAlgorithm():
def get_sid_filter(self):
return [self.sid]
def set_simulate_override(self, txn_sim_callable):
def set_transact_setter(self, txn_sim_callable):
pass
class TimeoutAlgorithm():
@@ -327,7 +327,7 @@ class TimeoutAlgorithm():
def get_sid_filter(self):
return [self.sid]
def set_simulate_override(self, txn_sim_callable):
def set_transact_setter(self, txn_sim_callable):
pass
class TestPrintAlgorithm():
@@ -354,7 +354,7 @@ class TestPrintAlgorithm():
def get_sid_filter(self):
return [self.sid]
def set_simulate_override(self, txn_sim_callable):
def set_transact_setter(self, txn_sim_callable):
pass
class TestLoggingAlgorithm():
@@ -381,7 +381,7 @@ class TestLoggingAlgorithm():
def get_sid_filter(self):
return [self.sid]
def set_simulate_override(self, txn_sim_callable):
def set_transact_setter(self, txn_sim_callable):
pass
+3 -3
View File
@@ -2,7 +2,7 @@ import zipline.utils.factory as factory
from zipline.test_algorithms import TestAlgorithm
from zipline.lines import SimulatedTrading
from zipline.finance.slippage import FixedSlippage, simulate_method_factory
from zipline.finance.slippage import FixedSlippage, transact_partial
from zipline.finance.commission import PerShare
def create_test_zipline(**config):
@@ -65,7 +65,7 @@ def create_test_zipline(**config):
slippage = config.get('slippage', FixedSlippage())
commission = PerShare()
sim_method = simulate_method_factory(slippage, commission)
transact_method = transact_partial(slippage, commission)
#-------------------
# Trade Source
@@ -106,7 +106,7 @@ def create_test_zipline(**config):
transforms,
test_algo,
trading_environment,
sim_method
transact_method
)
#-------------------