ENH: Extended commission PerShare method to allow a minimum cost per trade.

Also added unit tests (test_perf_tracking.TestCommissionEvents) to test
all commission models.
This commit is contained in:
Colin Alexander
2014-02-23 18:44:57 -08:00
committed by Eddie Hebert
parent ae4a9b7d96
commit 011ed09dc2
2 changed files with 40 additions and 6 deletions
+24
View File
@@ -33,6 +33,7 @@ import zipline.utils.math_utils as zp_math
from zipline.gens.composites import date_sorted_sources
from zipline.finance.trading import SimulationParameters
from zipline.finance.blotter import Order
from zipline.finance.commission import PerShare, PerTrade, PerDollar
from zipline.finance import trading
from zipline.protocol import DATASOURCE_TYPE
from zipline.utils.factory import create_random_simulation_parameters
@@ -172,6 +173,29 @@ class TestCommissionEvents(unittest.TestCase):
self.sim_params
)
# Test commission models and validate result
# Expected commission amounts:
# PerShare commission: 1.00, 1.00, 1.50 = $3.50
# PerTrade commission: 5.00, 5.00, 5.00 = $15.00
# PerDollar commission: 1.50, 3.00, 4.50 = $9.00
# Total commission = $3.50 + $15.00 + $9.00 = $27.50
# Create 3 transactions: 50, 100, 150 shares traded @ $20
transactions = [create_txn(events[0], 20, i)
for i in [50, 100, 150]]
# Create commission models
models = [PerShare(cost=0.01, min_trade_cost=1.00),
PerTrade(cost=5.00),
PerDollar(cost=0.0015)]
# Aggregate commission amounts
total_commission = 0
for model in models:
for trade in transactions:
total_commission += model.calculate(trade)[1]
self.assertEqual(total_commission, 27.5)
cash_adj_dt = self.sim_params.first_open \
+ datetime.timedelta(hours=3)
cash_adjustment = factory.create_commission(1, 300.0,
+16 -6
View File
@@ -17,28 +17,38 @@
class PerShare(object):
"""
Calculates a commission for a transaction based on a per
share cost.
share cost with an optional minimum cost per trade.
"""
def __init__(self, cost=0.03):
def __init__(self, cost=0.03, min_trade_cost=None):
"""
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.
min_trade_cost parameter is the minimum trade cost
regardless of the number of shares traded (e.g. $1.00).
"""
self.cost = float(cost)
self.min_trade_cost = None if min_trade_cost is None\
else float(min_trade_cost)
def __repr__(self):
return "{class_name}(cost={cost})".format(
class_name=self.__class__.__name__,
cost=self.cost)
return "{class_name}(cost={cost}, min trade cost={min_trade_cost})"\
.format(class_name=self.__class__.__name__,
cost=self.cost,
min_trade_cost=self.min_trade_cost)
def calculate(self, transaction):
"""
returns a tuple of:
(per share commission, total transaction commission)
"""
return self.cost, abs(transaction.amount * self.cost)
commission = abs(transaction.amount * self.cost)
if self.min_trade_cost is None:
return self.cost, commission
else:
commission = max(commission, self.min_trade_cost)
return abs(commission / transaction.amount), commission
class PerTrade(object):