Hello all,
Wanted to share/get feedback on some work I've done in simulating taxes using the commission API. Taxes are collected the first trading day of every year. And taxes are attached as commission when I purchase one stock of IBM. I never trade IBM otherwise. I haven't tried holding anything long term, so I haven't implemented that. And I assume fixed tax rates for all time, and don't handle dividends, because doing anything else seems to be really hard. Let me know what you think!
import zipline.finance.commission
stock_to_tax = symbol('IBM')
class CombinedCommissions(commission.PerShare):
def __init__(self, *commissions):
self.commissions = commissions
def calculate(self, transaction):
per_share = 0
total = 0
for c in self.commissions:
c_per_share, c_total = c.calculate(transaction)
per_share += c_per_share
total += c_total
return per_share, total
class ComputeProfitLoss(commission.PerShare):
def __init__(self, context):
self.context = context
def calculate(self, transaction):
# Recording profit/loss on taxed stock SID will result in following
# year's taxes being
if transaction.sid == stock_to_tax:
return 0.0, 0.0
# This will only work for long-only portfolios If portfolio has
# short positions, we will want to base taxibility on existence of
# position alone?
if transaction.amount > 0:
return 0.0, 0.0
position = self.context.portfolio.positions[transaction.sid]
if position:
pl = (transaction.price - position.cost_basis)*(-transaction.amount)
if pl < 0:
self.context.loss += pl
else:
# TODO Use position date to decide long vs short term
self.context.short_term_gain += pl
return 0.0, 0.0
class ApplyTax(commission.PerShare):
def __init__(self, context):
self.context = context
def calculate(self, transaction):
if transaction.sid == stock_to_tax and transaction.amount == 1:
st_taxable = self.context.short_term_gain + self.context.loss
lt_taxable = self.context.long_term_gain
self.context.short_term_gain = 0.0
self.context.long_term_gain = 0.0
self.context.loss = 0.0
if st_taxable < 0:
lt_taxable += st_taxable
st_taxable = 0
# Apply uniformly for all years, which is wrong
tax = st_taxable * 0.3 + lt_taxable * 0.15
if tax < 0:
tax = 0.0
log.info('Applying tax {0}'.format(tax))
return tax, tax
else:
return 0.0, 0.0
def apply_tax(context, data):
if get_datetime().month == 1:
order(stock_to_tax, 1)
else:
order_target_value(stock_to_tax, 0.0)
def initialize(context):
...
if arena == 'backtest':
set_commission(CombinedCommissions(commission.PerShare(cost=0.0075, min_trade_cost=1.00),
ComputeProfitLoss(context),
ApplyTax(context)))
schedule_function(apply_tax,
date_rule=date_rules.month_start(),
time_rule=time_rules.market_open(minutes=30))
...