mirror of
https://github.com/wassname/catalyst.git
synced 2026-08-12 11:50:11 +08:00
Cleaned up OOP, first round.
This commit is contained in:
+144
-149
@@ -5,21 +5,17 @@ import datetime
|
||||
import pytz
|
||||
|
||||
import zipline.utils.factory as factory
|
||||
import zipline.test_algorithms
|
||||
#import zipline.util as qutil
|
||||
import zipline.finance.performance as perf
|
||||
import zipline.finance.risk as risk
|
||||
import zipline.protocol as zp
|
||||
from zipline.finance.trading import TradeSimulationClient, TradingEnvironment, \
|
||||
SIMULATION_STYLE
|
||||
|
||||
from zipline.finance.trading import TradingEnvironment
|
||||
|
||||
class PerformanceTestCase(unittest.TestCase):
|
||||
|
||||
|
||||
def setUp(self):
|
||||
#qutil.configure_logging()
|
||||
self.benchmark_returns, self.treasury_curves = \
|
||||
factory.load_market_data()
|
||||
|
||||
|
||||
random_index = random.randint(
|
||||
0,
|
||||
len(self.treasury_curves)
|
||||
@@ -27,32 +23,32 @@ class PerformanceTestCase(unittest.TestCase):
|
||||
for n in range(100):
|
||||
self.dt = self.treasury_curves.keys()[random_index]
|
||||
self.end_dt = self.dt + datetime.timedelta(days=365)
|
||||
|
||||
|
||||
now = datetime.datetime.utcnow().replace(tzinfo=pytz.utc)
|
||||
|
||||
|
||||
if self.end_dt <= now:
|
||||
break
|
||||
|
||||
|
||||
self.trading_environment = TradingEnvironment(
|
||||
self.benchmark_returns,
|
||||
self.benchmark_returns,
|
||||
self.treasury_curves,
|
||||
period_start = self.dt,
|
||||
period_end = self.end_dt
|
||||
)
|
||||
|
||||
|
||||
self.onesec = datetime.timedelta(seconds=1)
|
||||
self.oneday = datetime.timedelta(days=1)
|
||||
self.tradingday = datetime.timedelta(hours=6, minutes=30)
|
||||
|
||||
|
||||
|
||||
|
||||
self.dt = self.trading_environment.trading_days[random_index]
|
||||
|
||||
|
||||
def tearDown(self):
|
||||
pass
|
||||
|
||||
|
||||
def test_long_position(self):
|
||||
"""
|
||||
verify that the performance period calculates properly for a
|
||||
verify that the performance period calculates properly for a
|
||||
single buy transaction
|
||||
"""
|
||||
#post some trades in the market
|
||||
@@ -63,30 +59,30 @@ class PerformanceTestCase(unittest.TestCase):
|
||||
self.onesec,
|
||||
self.trading_environment
|
||||
)
|
||||
|
||||
|
||||
txn = factory.create_txn(1,10.0,100,self.dt + self.onesec)
|
||||
pp = perf.PerformancePeriod({}, 0.0, 1000.0)
|
||||
|
||||
|
||||
pp.execute_transaction(txn)
|
||||
for trade in trades:
|
||||
pp.update_last_sale(trade)
|
||||
|
||||
|
||||
pp.calculate_performance()
|
||||
|
||||
|
||||
self.assertEqual(
|
||||
pp.period_capital_used,
|
||||
-1 * txn.price * txn.amount,
|
||||
"capital used should be equal to the opposite of the transaction \
|
||||
cost of sole txn in test"
|
||||
)
|
||||
|
||||
|
||||
self.assertEqual(len(pp.positions),1,"should be just one position")
|
||||
|
||||
|
||||
self.assertEqual(
|
||||
pp.positions[1].sid,
|
||||
txn.sid,
|
||||
txn.sid,
|
||||
"position should be in security with id 1")
|
||||
|
||||
|
||||
self.assertEqual(
|
||||
pp.positions[1].amount,
|
||||
txn.amount,
|
||||
@@ -94,13 +90,13 @@ class PerformanceTestCase(unittest.TestCase):
|
||||
sharecount=txn.amount
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
self.assertEqual(
|
||||
pp.positions[1].cost_basis,
|
||||
txn.price,
|
||||
"should have a cost basis of 10"
|
||||
)
|
||||
|
||||
|
||||
self.assertEqual(
|
||||
pp.positions[1].last_sale_price,
|
||||
trades[-1]['price'],
|
||||
@@ -110,16 +106,16 @@ class PerformanceTestCase(unittest.TestCase):
|
||||
act=pp.positions[1].last_sale_price
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
self.assertEqual(
|
||||
pp.ending_value,
|
||||
1100,
|
||||
"ending value should be price of last trade times number of \
|
||||
shares in position"
|
||||
)
|
||||
|
||||
|
||||
self.assertEqual(pp.pnl, 100, "gain of 1 on 100 shares should be 100")
|
||||
|
||||
|
||||
def test_short_position(self):
|
||||
"""verify that the performance period calculates properly for a \
|
||||
single short-sale transaction"""
|
||||
@@ -130,148 +126,148 @@ single short-sale transaction"""
|
||||
self.onesec,
|
||||
self.trading_environment
|
||||
)
|
||||
|
||||
|
||||
trades_1 = trades[:-2]
|
||||
|
||||
|
||||
txn = factory.create_txn(1, 10.0, -100, self.dt + self.onesec)
|
||||
pp = perf.PerformancePeriod({}, 0.0, 1000.0)
|
||||
|
||||
|
||||
pp.execute_transaction(txn)
|
||||
for trade in trades_1:
|
||||
pp.update_last_sale(trade)
|
||||
|
||||
|
||||
pp.calculate_performance()
|
||||
|
||||
|
||||
self.assertEqual(
|
||||
pp.period_capital_used,
|
||||
-1 * txn.price * txn.amount,
|
||||
"capital used should be equal to the opposite of the transaction\
|
||||
cost of sole txn in test"
|
||||
)
|
||||
|
||||
|
||||
self.assertEqual(
|
||||
len(pp.positions),
|
||||
1,
|
||||
"should be just one position")
|
||||
|
||||
|
||||
self.assertEqual(
|
||||
pp.positions[1].sid,
|
||||
txn.sid,
|
||||
txn.sid,
|
||||
"position should be in security from the transaction"
|
||||
)
|
||||
|
||||
|
||||
self.assertEqual(
|
||||
pp.positions[1].amount,
|
||||
-100,
|
||||
"should have a position of -100 shares"
|
||||
)
|
||||
|
||||
|
||||
self.assertEqual(
|
||||
pp.positions[1].cost_basis,
|
||||
txn.price,
|
||||
"should have a cost basis of 10"
|
||||
)
|
||||
|
||||
|
||||
self.assertEqual(
|
||||
pp.positions[1].last_sale_price,
|
||||
trades_1[-1]['price'],
|
||||
"last sale should be price of last trade"
|
||||
)
|
||||
|
||||
|
||||
self.assertEqual(
|
||||
pp.ending_value,
|
||||
-1100,
|
||||
"ending value should be price of last trade times number of \
|
||||
shares in position"
|
||||
)
|
||||
|
||||
|
||||
self.assertEqual(pp.pnl,-100,"gain of 1 on 100 shares should be 100")
|
||||
|
||||
# simulate additional trades, and ensure that the position value
|
||||
|
||||
# simulate additional trades, and ensure that the position value
|
||||
# reflects the new price
|
||||
trades_2 = trades[-2:]
|
||||
|
||||
|
||||
#simulate a rollover to a new period
|
||||
pp2 = perf.PerformancePeriod(
|
||||
pp.positions,
|
||||
pp.ending_value,
|
||||
pp.positions,
|
||||
pp.ending_value,
|
||||
pp.ending_cash
|
||||
)
|
||||
|
||||
|
||||
for trade in trades_2:
|
||||
pp2.update_last_sale(trade)
|
||||
|
||||
|
||||
pp2.calculate_performance()
|
||||
|
||||
|
||||
self.assertEqual(
|
||||
pp2.period_capital_used,
|
||||
0,
|
||||
"capital used should be zero, there were no transactions in \
|
||||
performance period"
|
||||
)
|
||||
|
||||
|
||||
self.assertEqual(
|
||||
len(pp2.positions),
|
||||
1,
|
||||
"should be just one position"
|
||||
)
|
||||
|
||||
|
||||
self.assertEqual(
|
||||
pp2.positions[1].sid,
|
||||
txn.sid,
|
||||
txn.sid,
|
||||
"position should be in security from the transaction"
|
||||
)
|
||||
|
||||
|
||||
self.assertEqual(
|
||||
pp2.positions[1].amount,
|
||||
-100,
|
||||
"should have a position of -100 shares"
|
||||
)
|
||||
|
||||
|
||||
self.assertEqual(
|
||||
pp2.positions[1].cost_basis,
|
||||
txn.price,
|
||||
"should have a cost basis of 10"
|
||||
)
|
||||
|
||||
|
||||
self.assertEqual(
|
||||
pp2.positions[1].last_sale_price,
|
||||
trades_2[-1].price,
|
||||
"last sale should be price of last trade"
|
||||
)
|
||||
|
||||
|
||||
self.assertEqual(
|
||||
pp2.ending_value,
|
||||
-900,
|
||||
"ending value should be price of last trade times number of \
|
||||
shares in position")
|
||||
|
||||
|
||||
self.assertEqual(
|
||||
pp2.pnl,
|
||||
200,
|
||||
"drop of 2 on -100 shares should be 200"
|
||||
)
|
||||
|
||||
|
||||
#now run a performance period encompassing the entire trade sample.
|
||||
ppTotal = perf.PerformancePeriod({}, 0.0, 1000.0)
|
||||
|
||||
|
||||
for trade in trades_1:
|
||||
ppTotal.update_last_sale(trade)
|
||||
|
||||
|
||||
ppTotal.execute_transaction(txn)
|
||||
|
||||
|
||||
for trade in trades_2:
|
||||
ppTotal.update_last_sale(trade)
|
||||
|
||||
|
||||
ppTotal.calculate_performance()
|
||||
|
||||
|
||||
self.assertEqual(
|
||||
ppTotal.period_capital_used,
|
||||
-1 * txn.price * txn.amount,
|
||||
"capital used should be equal to the opposite of the transaction \
|
||||
cost of sole txn in test"
|
||||
)
|
||||
|
||||
|
||||
self.assertEqual(
|
||||
len(ppTotal.positions),
|
||||
1,
|
||||
@@ -279,44 +275,44 @@ cost of sole txn in test"
|
||||
)
|
||||
self.assertEqual(
|
||||
ppTotal.positions[1].sid,
|
||||
txn.sid,
|
||||
txn.sid,
|
||||
"position should be in security from the transaction"
|
||||
)
|
||||
|
||||
|
||||
self.assertEqual(
|
||||
ppTotal.positions[1].amount,
|
||||
-100,
|
||||
"should have a position of -100 shares"
|
||||
)
|
||||
|
||||
|
||||
self.assertEqual(
|
||||
ppTotal.positions[1].cost_basis,
|
||||
txn.price,
|
||||
"should have a cost basis of 10"
|
||||
)
|
||||
|
||||
|
||||
self.assertEqual(
|
||||
ppTotal.positions[1].last_sale_price,
|
||||
trades_2[-1].price,
|
||||
"last sale should be price of last trade"
|
||||
)
|
||||
|
||||
|
||||
self.assertEqual(
|
||||
ppTotal.ending_value,
|
||||
-900,
|
||||
"ending value should be price of last trade times number of \
|
||||
shares in position")
|
||||
|
||||
|
||||
self.assertEqual(
|
||||
ppTotal.pnl,
|
||||
100,
|
||||
"drop of 1 on -100 shares should be 100"
|
||||
)
|
||||
|
||||
|
||||
def test_covering_short(self):
|
||||
"""verify performance where short is bought and covered, and shares \
|
||||
trade after cover"""
|
||||
|
||||
|
||||
trades = factory.create_trade_history(
|
||||
1,
|
||||
[10,10,10,11,9,8,7,8,9,10],
|
||||
@@ -324,104 +320,104 @@ trade after cover"""
|
||||
self.onesec,
|
||||
self.trading_environment
|
||||
)
|
||||
|
||||
|
||||
short_txn = factory.create_txn(
|
||||
1,
|
||||
10.0,
|
||||
-100,
|
||||
self.dt + self.onesec
|
||||
)
|
||||
|
||||
|
||||
cover_txn = factory.create_txn(1,7.0,100,self.dt + self.onesec * 6)
|
||||
pp = perf.PerformancePeriod({}, 0.0, 1000.0)
|
||||
|
||||
|
||||
pp.execute_transaction(short_txn)
|
||||
pp.execute_transaction(cover_txn)
|
||||
|
||||
|
||||
for trade in trades:
|
||||
pp.update_last_sale(trade)
|
||||
|
||||
|
||||
pp.calculate_performance()
|
||||
|
||||
|
||||
short_txn_cost = short_txn.price * short_txn.amount
|
||||
cover_txn_cost = cover_txn.price * cover_txn.amount
|
||||
|
||||
|
||||
self.assertEqual(
|
||||
pp.period_capital_used,
|
||||
-1 * short_txn_cost - cover_txn_cost,
|
||||
"capital used should be equal to the net transaction costs"
|
||||
)
|
||||
|
||||
|
||||
self.assertEqual(
|
||||
len(pp.positions),
|
||||
1,
|
||||
"should be just one position"
|
||||
)
|
||||
|
||||
|
||||
self.assertEqual(
|
||||
pp.positions[1].sid,
|
||||
short_txn.sid,
|
||||
short_txn.sid,
|
||||
"position should be in security from the transaction"
|
||||
)
|
||||
|
||||
|
||||
self.assertEqual(
|
||||
pp.positions[1].amount,
|
||||
0,
|
||||
"should have a position of -100 shares"
|
||||
)
|
||||
|
||||
|
||||
self.assertEqual(
|
||||
pp.positions[1].cost_basis,
|
||||
0,
|
||||
"a covered position should have a cost basis of 0"
|
||||
)
|
||||
|
||||
|
||||
self.assertEqual(
|
||||
pp.positions[1].last_sale_price,
|
||||
trades[-1].price,
|
||||
"last sale should be price of last trade"
|
||||
)
|
||||
|
||||
|
||||
self.assertEqual(
|
||||
pp.ending_value,
|
||||
0,
|
||||
"ending value should be price of last trade times number of \
|
||||
shares in position"
|
||||
)
|
||||
|
||||
|
||||
self.assertEqual(
|
||||
pp.pnl,
|
||||
pp.pnl,
|
||||
300,
|
||||
"gain of 1 on 100 shares should be 300"
|
||||
)
|
||||
|
||||
|
||||
def test_cost_basis_calc(self):
|
||||
trades = factory.create_trade_history(
|
||||
1,
|
||||
[10,11,11,12],
|
||||
[100,100,100,100],
|
||||
1,
|
||||
[10,11,11,12],
|
||||
[100,100,100,100],
|
||||
self.onesec,
|
||||
self.trading_environment
|
||||
)
|
||||
|
||||
|
||||
transactions = factory.create_txn_history(
|
||||
1,
|
||||
[10,11,11,12],
|
||||
[100,100,100,100],
|
||||
1,
|
||||
[10,11,11,12],
|
||||
[100,100,100,100],
|
||||
self.onesec,
|
||||
self.trading_environment
|
||||
)
|
||||
|
||||
|
||||
pp = perf.PerformancePeriod({}, 0.0, 1000.0)
|
||||
|
||||
|
||||
for txn in transactions:
|
||||
pp.execute_transaction(txn)
|
||||
|
||||
|
||||
for trade in trades:
|
||||
pp.update_last_sale(trade)
|
||||
|
||||
pp.update_last_sale(trade)
|
||||
|
||||
pp.calculate_performance()
|
||||
|
||||
|
||||
self.assertEqual(
|
||||
pp.positions[1].last_sale_price,
|
||||
trades[-1].price,
|
||||
@@ -429,72 +425,72 @@ shares in position"
|
||||
val=pp.positions[1].last_sale_price
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
self.assertEqual(
|
||||
pp.positions[1].cost_basis,
|
||||
11,
|
||||
"should have a cost basis of 11"
|
||||
)
|
||||
|
||||
|
||||
self.assertEqual(
|
||||
pp.pnl,
|
||||
pp.pnl,
|
||||
400
|
||||
)
|
||||
|
||||
|
||||
saleTxn = factory.create_txn(
|
||||
1,
|
||||
10.0,
|
||||
-100,
|
||||
self.dt + self.onesec * 4)
|
||||
|
||||
|
||||
down_tick = factory.create_trade(
|
||||
1,
|
||||
10.0,
|
||||
100,
|
||||
trades[-1].dt + self.onesec)
|
||||
|
||||
pp2 = perf.PerformancePeriod(
|
||||
copy.deepcopy(pp.positions),
|
||||
pp.ending_value,
|
||||
|
||||
pp2 = perf.PerformancePeriod(
|
||||
copy.deepcopy(pp.positions),
|
||||
pp.ending_value,
|
||||
pp.ending_cash
|
||||
)
|
||||
|
||||
|
||||
pp2.execute_transaction(saleTxn)
|
||||
pp2.update_last_sale(down_tick)
|
||||
|
||||
pp2.calculate_performance()
|
||||
|
||||
pp2.calculate_performance()
|
||||
self.assertEqual(
|
||||
pp2.positions[1].last_sale_price,
|
||||
10,
|
||||
"should have a last sale of 10, was {val}".format(val=pp2.positions[1].last_sale_price)
|
||||
)
|
||||
|
||||
|
||||
self.assertEqual(
|
||||
round(pp2.positions[1].cost_basis,2),
|
||||
11.33,
|
||||
"should have a cost basis of 11.33"
|
||||
)
|
||||
|
||||
|
||||
#print "second period pnl is {pnl}".format(pnl=pp2.pnl)
|
||||
self.assertEqual(pp2.pnl, -800, "this period goes from +400 to -400")
|
||||
|
||||
|
||||
pp3 = perf.PerformancePeriod({}, 0.0, 1000.0)
|
||||
|
||||
|
||||
transactions.append(saleTxn)
|
||||
for txn in transactions:
|
||||
pp3.execute_transaction(txn)
|
||||
|
||||
|
||||
trades.append(down_tick)
|
||||
for trade in trades:
|
||||
pp3.update_last_sale(trade)
|
||||
|
||||
|
||||
pp3.calculate_performance()
|
||||
self.assertEqual(
|
||||
pp3.positions[1].last_sale_price,
|
||||
10,
|
||||
"should have a last sale of 10"
|
||||
)
|
||||
|
||||
|
||||
self.assertEqual(
|
||||
round(pp3.positions[1].cost_basis,2),
|
||||
11.33,
|
||||
@@ -502,47 +498,47 @@ shares in position"
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
pp3.pnl,
|
||||
-400,
|
||||
pp3.pnl,
|
||||
-400,
|
||||
"should be -400 for all trades and transactions in period"
|
||||
)
|
||||
|
||||
def test_tracker(self):
|
||||
|
||||
|
||||
trade_count = 100
|
||||
sid = 133
|
||||
price = 10.1
|
||||
price = 10.1
|
||||
price_list = [price] * trade_count
|
||||
volume = [100] * trade_count
|
||||
trade_time_increment = datetime.timedelta(days=1)
|
||||
trade_history = factory.create_trade_history(
|
||||
sid,
|
||||
price_list,
|
||||
volume,
|
||||
trade_time_increment,
|
||||
self.trading_environment
|
||||
trade_history = factory.create_trade_history(
|
||||
sid,
|
||||
price_list,
|
||||
volume,
|
||||
trade_time_increment,
|
||||
self.trading_environment
|
||||
)
|
||||
|
||||
|
||||
sid2 = 134
|
||||
price2 = 12.12
|
||||
price2_list = [price2] * trade_count
|
||||
trade_history2 = factory.create_trade_history(
|
||||
sid2,
|
||||
price2_list,
|
||||
volume,
|
||||
trade_time_increment,
|
||||
self.trading_environment
|
||||
price2_list = [price2] * trade_count
|
||||
trade_history2 = factory.create_trade_history(
|
||||
sid2,
|
||||
price2_list,
|
||||
volume,
|
||||
trade_time_increment,
|
||||
self.trading_environment
|
||||
)
|
||||
|
||||
|
||||
trade_history.extend(trade_history2)
|
||||
|
||||
|
||||
self.trading_environment.period_start = trade_history[0].dt
|
||||
self.trading_environment.period_end = trade_history[-1].dt
|
||||
self.trading_environment.capital_base = 1000.0
|
||||
self.trading_environment.frame_index = ['sid', 'volume', 'dt', \
|
||||
'price', 'changed']
|
||||
perf_tracker = perf.PerformanceTracker(self.trading_environment)
|
||||
|
||||
|
||||
for event in trade_history:
|
||||
#create a transaction for all but
|
||||
#first trade in each sid, to simulate None transaction
|
||||
@@ -556,14 +552,13 @@ shares in position"
|
||||
})
|
||||
else:
|
||||
txn = None
|
||||
event[zp.TRANSFORM_TYPE.TRANSACTION] = txn
|
||||
event[zp.TRANSFORM_TYPE.TRANSACTION] = txn
|
||||
perf_tracker.process_event(event)
|
||||
|
||||
|
||||
#we skip two trades, to test case of None transaction
|
||||
txn_count = len(trade_history) - 2
|
||||
self.assertEqual(perf_tracker.txn_count, txn_count)
|
||||
|
||||
|
||||
cumulative_pos = perf_tracker.cumulative_performance.positions[sid]
|
||||
expected_size = txn_count / 2 * -25
|
||||
self.assertEqual(cumulative_pos.amount, expected_size)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user