mirror of
https://github.com/wassname/catalyst.git
synced 2026-07-19 11:22:06 +08:00
@@ -25,7 +25,7 @@ from unittest import TestCase
|
||||
from zipline.finance.slippage import VolumeShareSlippage
|
||||
|
||||
from zipline.protocol import Event, DATASOURCE_TYPE
|
||||
from zipline.gens.tradesimulation import Order
|
||||
from zipline.finance.blotter import Order
|
||||
|
||||
|
||||
class SlippageTestCase(TestCase):
|
||||
|
||||
@@ -34,7 +34,7 @@ from zipline.protocol import Event, DATASOURCE_TYPE
|
||||
import zipline.utils.factory as factory
|
||||
import zipline.utils.simfactory as simfactory
|
||||
|
||||
from zipline.gens.tradesimulation import Order, Blotter
|
||||
from zipline.finance.blotter import Blotter
|
||||
from zipline.gens.composites import date_sorted_sources
|
||||
|
||||
import zipline.finance.trading as trading
|
||||
@@ -315,13 +315,9 @@ class FinanceTestCase(TestCase):
|
||||
|
||||
order_date = start_date
|
||||
for i in xrange(order_count):
|
||||
order = Order(**{
|
||||
'sid': sid,
|
||||
'amount': order_amount * alternator ** i,
|
||||
'dt': order_date
|
||||
})
|
||||
|
||||
blotter.place_order(order)
|
||||
blotter.set_date(order_date)
|
||||
blotter.order(sid, order_amount * alternator ** i, None, None)
|
||||
|
||||
order_date = order_date + order_interval
|
||||
# move after market orders to just after market next
|
||||
|
||||
@@ -29,7 +29,7 @@ from zipline.finance.slippage import Transaction, create_transaction
|
||||
|
||||
from zipline.gens.composites import date_sorted_sources
|
||||
from zipline.finance.trading import SimulationParameters
|
||||
from zipline.gens.tradesimulation import Order
|
||||
from zipline.finance.blotter import Order
|
||||
import zipline.finance.trading as trading
|
||||
from zipline.protocol import DATASOURCE_TYPE
|
||||
from zipline.utils.factory import create_random_simulation_parameters
|
||||
|
||||
@@ -38,6 +38,7 @@ from zipline.finance.slippage import (
|
||||
transact_partial
|
||||
)
|
||||
from zipline.finance.commission import PerShare, PerTrade
|
||||
from zipline.finance.blotter import Blotter
|
||||
from zipline.finance.constants import ANNUALIZER
|
||||
import zipline.finance.trading as trading
|
||||
import zipline.protocol
|
||||
@@ -85,7 +86,6 @@ class TradingAlgorithm(object):
|
||||
capital_base : float <default: 1.0e5>
|
||||
How much capital to start with.
|
||||
"""
|
||||
self.order = None
|
||||
self._portfolio = None
|
||||
self.datetime = None
|
||||
|
||||
@@ -115,6 +115,8 @@ class TradingAlgorithm(object):
|
||||
|
||||
self.sim_params = kwargs.pop('sim_params', None)
|
||||
|
||||
self.blotter = kwargs.pop('blotter', Blotter())
|
||||
|
||||
# an algorithm subclass needs to set initialized to True when
|
||||
# it is fully initialized.
|
||||
self.initialized = False
|
||||
@@ -318,6 +320,9 @@ class TradingAlgorithm(object):
|
||||
for name, value in kwargs.items():
|
||||
self._recorded_vars[name] = value
|
||||
|
||||
def order(self, sid, amount, limit_price=None, stop_price=None):
|
||||
return self.blotter.order(sid, amount, limit_price, stop_price)
|
||||
|
||||
@property
|
||||
def recorded_vars(self):
|
||||
return copy(self._recorded_vars)
|
||||
@@ -329,9 +334,6 @@ class TradingAlgorithm(object):
|
||||
def set_portfolio(self, portfolio):
|
||||
self._portfolio = portfolio
|
||||
|
||||
def set_order(self, order_callable):
|
||||
self.order = order_callable
|
||||
|
||||
def set_logger(self, logger):
|
||||
self.logger = logger
|
||||
|
||||
@@ -356,7 +358,7 @@ class TradingAlgorithm(object):
|
||||
Set the method that will be called to create a
|
||||
transaction from open orders and trade events.
|
||||
"""
|
||||
self.trading_client.blotter.transact = transact
|
||||
self.blotter.transact = transact
|
||||
|
||||
def set_slippage(self, slippage):
|
||||
if not isinstance(slippage, (VolumeShareSlippage, FixedSlippage)):
|
||||
|
||||
@@ -0,0 +1,235 @@
|
||||
#
|
||||
# Copyright 2013 Quantopian, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
import math
|
||||
import uuid
|
||||
|
||||
from copy import copy
|
||||
from logbook import Logger
|
||||
from collections import defaultdict
|
||||
|
||||
from zipline.protocol import DATASOURCE_TYPE
|
||||
from zipline.protocol import Order as zpOrder
|
||||
|
||||
from zipline.finance.slippage import (
|
||||
VolumeShareSlippage,
|
||||
transact_partial,
|
||||
check_order_triggers
|
||||
)
|
||||
from zipline.finance.commission import PerShare
|
||||
import zipline.utils.math_utils as zp_math
|
||||
|
||||
log = Logger('Blotter')
|
||||
|
||||
from zipline.utils.protocol_utils import Enum
|
||||
|
||||
ORDER_STATUS = Enum(
|
||||
'OPEN',
|
||||
'FILLED',
|
||||
'CANCELLED'
|
||||
)
|
||||
|
||||
|
||||
class Blotter(object):
|
||||
|
||||
def __init__(self):
|
||||
self.transact = transact_partial(VolumeShareSlippage(), PerShare())
|
||||
# these orders are aggregated by sid
|
||||
self.open_orders = defaultdict(list)
|
||||
# keep a dict of orders by their own id
|
||||
self.orders = {}
|
||||
# holding orders that have come in since the last
|
||||
# event.
|
||||
self.new_orders = []
|
||||
self.current_dt = None
|
||||
|
||||
def set_date(self, dt):
|
||||
self.current_dt = dt
|
||||
|
||||
def order(self, sid, amount, limit_price, stop_price):
|
||||
|
||||
# something could be done with amount to further divide
|
||||
# between buy by share count OR buy shares up to a dollar amount
|
||||
# numeric == share count AND "$dollar.cents" == cost amount
|
||||
|
||||
"""
|
||||
amount > 0 :: Buy/Cover
|
||||
amount < 0 :: Sell/Short
|
||||
Market order: order(sid, amount)
|
||||
Limit order: order(sid, amount, limit_price)
|
||||
Stop order: order(sid, amount, None, stop_price)
|
||||
StopLimit order: order(sid, amount, limit_price, stop_price)
|
||||
"""
|
||||
|
||||
# just validates amount and passes rest on to TransactionSimulator
|
||||
# Tell the user if they try to buy 0 shares of something.
|
||||
if amount == 0:
|
||||
zero_message = "Requested to trade zero shares of {psid}".format(
|
||||
psid=sid
|
||||
)
|
||||
log.debug(zero_message)
|
||||
# Don't bother placing orders for 0 shares.
|
||||
return
|
||||
|
||||
order = Order(**{
|
||||
'dt': self.current_dt,
|
||||
'sid': sid,
|
||||
'amount': int(amount),
|
||||
'filled': 0,
|
||||
'stop': stop_price,
|
||||
'limit': limit_price
|
||||
})
|
||||
|
||||
# initialized filled field.
|
||||
order.filled = 0
|
||||
self.open_orders[order.sid].append(order)
|
||||
self.orders[order.id] = order
|
||||
self.new_orders.append(order)
|
||||
|
||||
return order.id
|
||||
|
||||
def cancel(self, order_id):
|
||||
cur_order = self.orders[order_id]
|
||||
if cur_order.open:
|
||||
order_list = self.open_orders[cur_order.sid]
|
||||
if cur_order in order_list:
|
||||
order_list.remove(cur_order)
|
||||
|
||||
if cur_order in self.new_orders:
|
||||
self.new_orders.remove(cur_order)
|
||||
cur_order.status = ORDER_STATUS.CANCELLED
|
||||
cur_order.dt = self.current_dt
|
||||
# we want this order's new status to be relayed out
|
||||
# along with newly placed orders.
|
||||
self.new_orders.append(cur_order)
|
||||
|
||||
def process_trade(self, trade_event):
|
||||
if trade_event.type != DATASOURCE_TYPE.TRADE:
|
||||
return [], []
|
||||
|
||||
if zp_math.tolerant_equals(trade_event.volume, 0):
|
||||
# there are zero volume trade_events bc some stocks trade
|
||||
# less frequently than once per minute.
|
||||
return [], []
|
||||
|
||||
if trade_event.sid in self.open_orders:
|
||||
orders = self.open_orders[trade_event.sid]
|
||||
orders = sorted(orders, key=lambda o: o.dt)
|
||||
# Only use orders for the current day or before
|
||||
current_orders = filter(
|
||||
lambda o: o.dt <= trade_event.dt,
|
||||
orders)
|
||||
else:
|
||||
return [], []
|
||||
|
||||
txns = self.transact(trade_event, current_orders)
|
||||
for txn in txns:
|
||||
self.orders[txn.order_id].filled += txn.amount
|
||||
# mark the date of the order to match the transaction
|
||||
# that is filling it.
|
||||
self.orders[txn.order_id].dt = txn.dt
|
||||
|
||||
modified_orders = [order for order
|
||||
in self.open_orders[trade_event.sid]
|
||||
if order.dt == trade_event.dt]
|
||||
|
||||
# update the open orders for the trade_event's sid
|
||||
self.open_orders[trade_event.sid] = \
|
||||
[order for order
|
||||
in self.open_orders[trade_event.sid]
|
||||
if order.open]
|
||||
|
||||
return txns, modified_orders
|
||||
|
||||
|
||||
class Order(object):
|
||||
def __init__(self, dt, sid, amount, stop=None, limit=None, filled=0):
|
||||
"""
|
||||
@dt - datetime.datetime that the order was placed
|
||||
@sid - stock sid of the order
|
||||
@amount - the number of shares to buy/sell
|
||||
a positive sign indicates a buy
|
||||
a negative sign indicates a sell
|
||||
@filled - how many shares of the order have been filled so far
|
||||
"""
|
||||
# get a string representation of the uuid.
|
||||
self.id = self.make_id()
|
||||
self.dt = dt
|
||||
self.created = dt
|
||||
self.sid = sid
|
||||
self.amount = amount
|
||||
self.filled = filled
|
||||
self.status = ORDER_STATUS.OPEN
|
||||
self.stop = stop
|
||||
self.limit = limit
|
||||
self.stop_reached = False
|
||||
self.limit_reached = False
|
||||
self.direction = math.copysign(1, self.amount)
|
||||
self.type = DATASOURCE_TYPE.ORDER
|
||||
|
||||
def make_id(self):
|
||||
return uuid.uuid4().get_hex()
|
||||
|
||||
def to_dict(self):
|
||||
py = copy(self.__dict__)
|
||||
for field in ['type', 'direction']:
|
||||
del py[field]
|
||||
return py
|
||||
|
||||
def to_api_obj(self):
|
||||
pydict = self.to_dict()
|
||||
obj = zpOrder(initial_values=pydict)
|
||||
return obj
|
||||
|
||||
def check_triggers(self, event):
|
||||
"""
|
||||
Update internal state based on price triggers and the
|
||||
trade event's price.
|
||||
"""
|
||||
stop_reached, limit_reached = \
|
||||
check_order_triggers(self, event)
|
||||
if (stop_reached, limit_reached) \
|
||||
!= (self.stop_reached, self.limit_reached):
|
||||
self.dt = event.dt
|
||||
self.stop_reached = stop_reached
|
||||
self.limit_reached = limit_reached
|
||||
|
||||
@property
|
||||
def open(self):
|
||||
if self.status == ORDER_STATUS.CANCELLED:
|
||||
return False
|
||||
|
||||
remainder = self.amount - self.filled
|
||||
if remainder != 0:
|
||||
self.status = ORDER_STATUS.OPEN
|
||||
else:
|
||||
self.status = ORDER_STATUS.FILLED
|
||||
|
||||
return self.status == ORDER_STATUS.OPEN
|
||||
|
||||
@property
|
||||
def triggered(self):
|
||||
"""
|
||||
For a market order, True.
|
||||
For a stop order, True IFF stop_reached.
|
||||
For a limit order, True IFF limit_reached.
|
||||
For a stop-limit order, True IFF (stop_reached AND limit_reached)
|
||||
"""
|
||||
if self.stop and not self.stop_reached:
|
||||
return False
|
||||
|
||||
if self.limit and not self.limit_reached:
|
||||
return False
|
||||
|
||||
return True
|
||||
@@ -13,10 +13,6 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
import itertools
|
||||
import math
|
||||
import uuid
|
||||
|
||||
from copy import copy
|
||||
from itertools import chain
|
||||
from logbook import Logger, Processor
|
||||
from collections import defaultdict
|
||||
@@ -25,177 +21,8 @@ from zipline.protocol import BarData, DATASOURCE_TYPE
|
||||
from zipline.finance.performance import PerformanceTracker
|
||||
from zipline.gens.utils import hash_args
|
||||
|
||||
from zipline.finance.slippage import (
|
||||
VolumeShareSlippage,
|
||||
transact_partial,
|
||||
check_order_triggers
|
||||
)
|
||||
from zipline.finance.commission import PerShare
|
||||
import zipline.utils.math_utils as zp_math
|
||||
|
||||
log = Logger('Trade Simulation')
|
||||
|
||||
from zipline.utils.protocol_utils import Enum
|
||||
|
||||
ORDER_STATUS = Enum(
|
||||
'OPEN',
|
||||
'FILLED'
|
||||
)
|
||||
|
||||
|
||||
class Blotter(object):
|
||||
|
||||
def __init__(self):
|
||||
self.transact = transact_partial(VolumeShareSlippage(), PerShare())
|
||||
# these orders are aggregated by sid
|
||||
self.open_orders = defaultdict(list)
|
||||
# keep a dict of orders by their own id
|
||||
self.orders = {}
|
||||
# holding orders that have come in since the last
|
||||
# event.
|
||||
self.new_orders = []
|
||||
|
||||
def place_order(self, order):
|
||||
# initialized filled field.
|
||||
order.filled = 0
|
||||
self.open_orders[order.sid].append(order)
|
||||
self.orders[order.id] = order
|
||||
self.new_orders.append(order)
|
||||
|
||||
def transform(self, stream_in):
|
||||
"""
|
||||
Main generator work loop.
|
||||
"""
|
||||
for date, snapshot in stream_in:
|
||||
results = []
|
||||
|
||||
for event in snapshot:
|
||||
results.append(event)
|
||||
# We only fill transactions on trade events.
|
||||
if event.type == DATASOURCE_TYPE.TRADE:
|
||||
txns, modified_orders = self.process_trade(event)
|
||||
results.extend(chain(txns, modified_orders))
|
||||
|
||||
yield date, results
|
||||
|
||||
def process_trade(self, trade_event):
|
||||
if trade_event.type != DATASOURCE_TYPE.TRADE:
|
||||
return [], []
|
||||
|
||||
if zp_math.tolerant_equals(trade_event.volume, 0):
|
||||
# there are zero volume trade_events bc some stocks trade
|
||||
# less frequently than once per minute.
|
||||
return [], []
|
||||
|
||||
if trade_event.sid in self.open_orders:
|
||||
orders = self.open_orders[trade_event.sid]
|
||||
orders = sorted(orders, key=lambda o: o.dt)
|
||||
# Only use orders for the current day or before
|
||||
current_orders = filter(
|
||||
lambda o: o.dt <= trade_event.dt,
|
||||
orders)
|
||||
else:
|
||||
return [], []
|
||||
|
||||
txns = self.transact(trade_event, current_orders)
|
||||
for txn in txns:
|
||||
self.orders[txn.order_id].filled += txn.amount
|
||||
# mark the date of the order to match the transaction
|
||||
# that is filling it.
|
||||
self.orders[txn.order_id].dt = txn.dt
|
||||
|
||||
modified_orders = [order for order
|
||||
in self.open_orders[trade_event.sid]
|
||||
if order.dt == trade_event.dt]
|
||||
for order in modified_orders:
|
||||
if not order.open:
|
||||
del self.orders[order.id]
|
||||
|
||||
# update the open orders for the trade_event's sid
|
||||
self.open_orders[trade_event.sid] = \
|
||||
[order for order
|
||||
in self.open_orders[trade_event.sid]
|
||||
if order.open]
|
||||
|
||||
return txns, modified_orders
|
||||
|
||||
|
||||
class Order(object):
|
||||
def __init__(self, dt, sid, amount, stop=None, limit=None, filled=0):
|
||||
"""
|
||||
@dt - datetime.datetime that the order was placed
|
||||
@sid - stock sid of the order
|
||||
@amount - the number of shares to buy/sell
|
||||
a positive sign indicates a buy
|
||||
a negative sign indicates a sell
|
||||
@filled - how many shares of the order have been filled so far
|
||||
"""
|
||||
# get a string representation of the uuid.
|
||||
self.id = self.make_id()
|
||||
self.dt = dt
|
||||
self.created = dt
|
||||
self.sid = sid
|
||||
self.amount = amount
|
||||
self.filled = filled
|
||||
self.status = ORDER_STATUS.OPEN
|
||||
self.stop = stop
|
||||
self.limit = limit
|
||||
self.stop_reached = False
|
||||
self.limit_reached = False
|
||||
self.direction = math.copysign(1, self.amount)
|
||||
self.type = DATASOURCE_TYPE.ORDER
|
||||
|
||||
def make_id(self):
|
||||
return uuid.uuid4().get_hex()
|
||||
|
||||
def to_dict(self):
|
||||
py = copy(self.__dict__)
|
||||
for field in ['type', 'direction']:
|
||||
del py[field]
|
||||
return py
|
||||
|
||||
def check_triggers(self, event):
|
||||
"""
|
||||
Update internal state based on price triggers and the
|
||||
trade event's price.
|
||||
"""
|
||||
stop_reached, limit_reached = \
|
||||
check_order_triggers(self, event)
|
||||
if (stop_reached, limit_reached) \
|
||||
!= (self.stop_reached, self.limit_reached):
|
||||
self.dt = event.dt
|
||||
self.stop_reached = stop_reached
|
||||
self.limit_reached = limit_reached
|
||||
|
||||
@property
|
||||
def open(self):
|
||||
remainder = self.amount - self.filled
|
||||
if remainder != 0:
|
||||
self.status = ORDER_STATUS.OPEN
|
||||
else:
|
||||
self.status = ORDER_STATUS.FILLED
|
||||
|
||||
return self.status == ORDER_STATUS.OPEN
|
||||
|
||||
@property
|
||||
def triggered(self):
|
||||
"""
|
||||
For a market order, True.
|
||||
For a stop order, True IFF stop_reached.
|
||||
For a limit order, True IFF limit_reached.
|
||||
For a stop-limit order, True IFF (stp_reached AND limit_reached)
|
||||
"""
|
||||
if self.stop and not self.stop_reached:
|
||||
return False
|
||||
|
||||
if self.limit and not self.limit_reached:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def __getitem__(self, name):
|
||||
return self.__dict__[name]
|
||||
|
||||
|
||||
class AlgorithmSimulator(object):
|
||||
|
||||
@@ -211,15 +38,13 @@ class AlgorithmSimulator(object):
|
||||
"""
|
||||
return self.__class__.__name__ + hash_args()
|
||||
|
||||
def __init__(self, algo, sim_params, blotter=None):
|
||||
def __init__(self, algo, sim_params):
|
||||
|
||||
# ==============
|
||||
# Simulation
|
||||
# Param Setup
|
||||
# ==============
|
||||
self.sim_params = sim_params
|
||||
if not blotter:
|
||||
self.blotter = Blotter()
|
||||
|
||||
# ==============
|
||||
# Perf Tracker
|
||||
@@ -239,10 +64,6 @@ class AlgorithmSimulator(object):
|
||||
second=0,
|
||||
microsecond=0)
|
||||
|
||||
# Monkey patch the user algorithm to place orders in the
|
||||
# TransactionSimulator's order book and use our logger.
|
||||
self.algo.set_order(self.order)
|
||||
|
||||
# ==============
|
||||
# Snapshot Setup
|
||||
# ==============
|
||||
@@ -268,49 +89,6 @@ class AlgorithmSimulator(object):
|
||||
record.extra['algo_dt'] = self.snapshot_dt
|
||||
self.processor = Processor(inject_algo_dt)
|
||||
|
||||
def order(self, sid, amount, limit_price=None, stop_price=None):
|
||||
|
||||
# something could be done with amount to further divide
|
||||
# between buy by share count OR buy shares up to a dollar amount
|
||||
# numeric == share count AND "$dollar.cents" == cost amount
|
||||
|
||||
"""
|
||||
amount > 0 :: Buy/Cover
|
||||
amount < 0 :: Sell/Short
|
||||
Market order: order(sid, amount)
|
||||
Limit order: order(sid, amount, limit_price)
|
||||
Stop order: order(sid, amount, None, stop_price)
|
||||
StopLimit order: order(sid, amount, limit_price, stop_price)
|
||||
"""
|
||||
|
||||
# just validates amount and passes rest on to TransactionSimulator
|
||||
# Tell the user if they try to buy 0 shares of something.
|
||||
if amount == 0:
|
||||
zero_message = "Requested to trade zero shares of {psid}".format(
|
||||
psid=sid
|
||||
)
|
||||
log.debug(zero_message)
|
||||
# Don't bother placing orders for 0 shares.
|
||||
return
|
||||
|
||||
order = Order(**{
|
||||
'dt': self.simulation_dt,
|
||||
'sid': sid,
|
||||
'amount': int(amount),
|
||||
'filled': 0,
|
||||
'stop': stop_price,
|
||||
'limit': limit_price
|
||||
})
|
||||
|
||||
# Add non-zero orders to the order book.
|
||||
# !!!IMPORTANT SIDE-EFFECT!!!
|
||||
# This modifies the internal state of the blotter
|
||||
# so that it can fill the placed order when it
|
||||
# receives its next message.
|
||||
self.blotter.place_order(order)
|
||||
|
||||
return order.id
|
||||
|
||||
def transform(self, stream_in):
|
||||
"""
|
||||
Main generator work loop.
|
||||
@@ -332,6 +110,7 @@ class AlgorithmSimulator(object):
|
||||
bm_updated = False
|
||||
for date, snapshot in stream:
|
||||
self.perf_tracker.set_date(date)
|
||||
self.algo.blotter.set_date(date)
|
||||
# If we're still in the warmup period. Use the event to
|
||||
# update our universe, but don't yield any perf messages,
|
||||
# and don't send a snapshot to handle_data.
|
||||
@@ -351,7 +130,7 @@ class AlgorithmSimulator(object):
|
||||
updated = True
|
||||
if event.type == DATASOURCE_TYPE.BENCHMARK:
|
||||
bm_updated = True
|
||||
txns, orders = self.blotter.process_trade(event)
|
||||
txns, orders = self.algo.blotter.process_trade(event)
|
||||
for data in chain([event], txns, orders):
|
||||
self.perf_tracker.process_event(data)
|
||||
|
||||
@@ -368,9 +147,9 @@ class AlgorithmSimulator(object):
|
||||
# above through perf tracker before emitting
|
||||
# the perf packet, so that the perf includes
|
||||
# placed orders
|
||||
for order in self.blotter.new_orders:
|
||||
for order in self.algo.blotter.new_orders:
|
||||
self.perf_tracker.process_event(order)
|
||||
self.blotter.new_orders = []
|
||||
self.algo.blotter.new_orders = []
|
||||
|
||||
# The benchmark is our internal clock. When it
|
||||
# updates, we need to emit a performance message.
|
||||
|
||||
@@ -62,6 +62,10 @@ class Event(object):
|
||||
return "Event({0})".format(self.__dict__)
|
||||
|
||||
|
||||
class Order(Event):
|
||||
pass
|
||||
|
||||
|
||||
class Portfolio(object):
|
||||
|
||||
def __init__(self, initial_values=None):
|
||||
|
||||
@@ -148,12 +148,6 @@ class ExceptionAlgorithm(TradingAlgorithm):
|
||||
else:
|
||||
pass
|
||||
|
||||
def set_order(self, order_callable):
|
||||
if self.throw_from == "set_order":
|
||||
raise Exception("Algo exception in set_order")
|
||||
else:
|
||||
pass
|
||||
|
||||
def set_portfolio(self, portfolio):
|
||||
if self.throw_from == "set_portfolio":
|
||||
raise Exception("Algo exception in set_portfolio")
|
||||
|
||||
@@ -3,7 +3,7 @@ import blist
|
||||
from zipline.utils.date_utils import EPOCH
|
||||
from itertools import izip
|
||||
from logbook import FileHandler
|
||||
from zipline.gens.tradesimulation import ORDER_STATUS
|
||||
from zipline.finance.blotter import ORDER_STATUS
|
||||
|
||||
|
||||
def setup_logger(test, path='test.log'):
|
||||
|
||||
Reference in New Issue
Block a user