def test_broker_add_position_enough_cash(): broker = Broker(initial_cash=100) pos = broker.add_position('FOO', price=10, amount=1, bar_index=0) assert pos.entry_price() == 10 assert pos.size() == 1
def __init__(self): self.feeds = [] self.all_bars = [] self.broker = Broker() self.bars = None self.trade_size = 1 self.analyzers = { 'stats': StatsAnalyzer(self), 'tradeslist': TradesListAnalyzer(self), 'equity': EquityAnalyzer(self) }
def test_broker_close_position_with_commission(): broker = Broker(initial_cash=100) broker.set_commission(percentage=1) # 1% pos = broker.add_position('FOO', price=10, amount=1, bar_index=0) broker.close_position(pos, price=12, bar_index=1) assert broker.cash() == 100 + 2 - (10 + 12) * 0.01
def test_broker_close_position_places_it_in_retired_list(): broker = Broker(initial_cash=100) pos = broker.add_position('FOO', price=10, amount=1, bar_index=0) broker.close_position(pos, price=12, bar_index=1) assert pos not in broker.all_positions() assert pos in broker.retired_positions()
def test_broker_close_position(): broker = Broker(initial_cash=100) pos = broker.add_position('FOO', price=10, amount=1, bar_index=0) broker.close_position(pos, price=12, bar_index=1) assert broker.cash() == 100 + 2
def test_broker_percentage_commissions(): broker = Broker(initial_cash=100) broker.set_commission(percentage=0.05) # 0.05% pos = broker.add_position('FOO', price=10, amount=1, bar_index=0) should_be_cash = 100 - 10 - 10 * 0.01 * 0.05 assert (broker.cash() - should_be_cash) < 0.00001
def test_broker_cash(): broker = Broker(initial_cash=100000.) assert broker.cash() == 100000.
def test_broker_all_position(): broker = Broker(initial_cash=100) pos = broker.add_position('FOO', price=10, amount=1, bar_index=0) assert pos in broker.all_positions()
def test_broker_add_position_not_enough_cash(): broker = Broker(initial_cash=100) pos = broker.add_position('FOO', price=1000, amount=1, bar_index=0) assert pos is None
class Strategy: """ """ def __init__(self): self.feeds = [] self.all_bars = [] self.broker = Broker() self.bars = None self.trade_size = 1 self.analyzers = { 'stats': StatsAnalyzer(self), 'tradeslist': TradesListAnalyzer(self), 'equity': EquityAnalyzer(self) } def get_analyzer(self, analyzer_id): return self.analyzers[analyzer_id] def add_feed(self, feed): """ Adds feed to feeds list. """ self.feeds.append(feed) def set_trade_size(self, size): self.trade_size = math.floor(size) @abstractmethod def execute(self): """ Will be called by 'run' """ pass def run(self, from_time=None, to_time=None): """ By default, just calls execute. """ self._prepare_bars(from_time, to_time) if len(self.all_bars) > 0: self.bars = self.all_bars[0] self.execute() def set_current_ticker(self, ticker): self.bars = self._get_bars(ticker) def _prepare_bars(self, from_time, to_time): if len(self.feeds) == 0: raise NaibackException('No feeds added to strategy') self.all_bars.clear() for feed in self.feeds: if from_time is None or to_time is None: self.all_bars.append(Bars.from_feed(feed)) else: self.all_bars.append( Bars.from_feed_filter(feed, from_time, to_time)) all_dates = list(sorted(self._combine_dates())) for bars in self.all_bars: self._synchronize_bars(bars, all_dates) bars.index = range(0, len(bars.close)) def get_bars(self, ticker): return self._get_bars(ticker) def _get_bars(self, ticker): for bars in self.all_bars: if bars.ticker == ticker: return bars return None def last_position(self): return self.broker.last_position() def all_positions(self): return self.broker.all_positions() def last_position_is_active(self): return self.broker.last_position_is_active() def _synchronize_bars(self, bars, all_dates): bar_pos = 0 open_ = 0 high = 0 low = 0 close = 0 volume = bars.volume[bar_pos] for dt in all_dates: if len(bars.timestamp) > bar_pos: print("new close: {} ({})".format(close, dt)) if bars.timestamp[bar_pos] > dt: print("Inserting at {}: {}".format(dt, close)) bars.insert_bar(bar_pos, open_, high, low, close, volume, dt) else: open_ = bars.open[bar_pos] high = bars.high[bar_pos] low = bars.low[bar_pos] close = bars.close[bar_pos] volume = bars.volume[bar_pos] if bars.timestamp[bar_pos] > dt: bars.insert_bar(bar_pos, open_, high, low, close, volume, dt) print("new close: {} ({})".format(close, dt)) else: bars.insert_bar(bar_pos, open_, high, low, close, volume, dt) print("Inserting[2] at {}: {}".format(dt, close)) bar_pos += 1 def _combine_dates(self): dates = set() for bars in self.all_bars: dates.update(bars.timestamp) return dates def buy_at_open(self, bar, ticker=None): if ticker is None: ticker = 0 if isinstance(ticker, int): ticker = self.all_bars[ticker].ticker bars = self._get_bars(ticker) self.broker.set_timestamp(bars.timestamp[bar]) return self.broker.add_position(ticker, bars.open[bar], self.trade_size, bar) def buy_at_limit(self, bar, price, ticker=None): if ticker is None: ticker = 0 if isinstance(ticker, int): ticker = self.all_bars[ticker].ticker bars = self._get_bars(ticker) self.broker.set_timestamp(bars.timestamp[bar]) if bars.low[bar] <= price: if bars.open[bar] > price: return self.broker.add_position(ticker, price, self.trade_size, bar) else: return self.broker.add_position(ticker, bars.open[bar], self.trade_size, bar) else: return None def buy_at_stop(self, bar, price, ticker=None): if ticker is None: ticker = 0 if isinstance(ticker, int): ticker = self.all_bars[ticker].ticker bars = self._get_bars(ticker) self.broker.set_timestamp(bars.timestamp[bar]) if bars.high[bar] >= price: if bars.open[bar] < price: return self.broker.add_position(ticker, price, self.trade_size, bar) else: return self.broker.add_position(ticker, bars.open[bar], self.trade_size, bar) else: return None def buy_at_close(self, bar, ticker=None): if ticker is None: ticker = 0 if isinstance(ticker, int): ticker = self.all_bars[ticker].ticker bars = self._get_bars(ticker) self.broker.set_timestamp(bars.timestamp[bar]) return self.broker.add_position(ticker, bars.close[bar], self.trade_size, bar) def short_at_open(self, bar, ticker=None): if ticker is None: ticker = 0 if isinstance(ticker, int): ticker = self.all_bars[ticker].ticker bars = self._get_bars(ticker) self.broker.set_timestamp(bars.timestamp[bar]) return self.broker.add_position(ticker, bars.open[bar], -self.trade_size, bar) def short_at_limit(self, bar, price, ticker=None): if ticker is None: ticker = 0 if isinstance(ticker, int): ticker = self.all_bars[ticker].ticker bars = self._get_bars(ticker) self.broker.set_timestamp(bars.timestamp[bar]) if bars.high[bar] >= price: if bars.open[bar] < price: return self.broker.add_position(ticker, price, -self.trade_size, bar) else: return self.broker.add_position(ticker, bars.open[bar], -self.trade_size, bar) else: return None def short_at_stop(self, bar, price, ticker=None): if ticker is None: ticker = 0 if isinstance(ticker, int): ticker = self.all_bars[ticker].ticker bars = self._get_bars(ticker) self.broker.set_timestamp(bars.timestamp[bar]) if bars.low[bar] <= price: if bars.open[bar] > price: return self.broker.add_position(ticker, price, -self.trade_size, bar) else: return self.broker.add_position(ticker, bars.open[bar], -self.trade_size, bar) else: return None def short_at_close(self, bar, ticker=None): if ticker is None: ticker = 0 if isinstance(ticker, int): ticker = self.all_bars[ticker].ticker bars = self._get_bars(ticker) self.broker.set_timestamp(bars.timestamp[bar]) return self.broker.add_position(ticker, bars.close[bar], -self.trade_size, bar) def exit_at_open(self, bar, pos): bars = self._get_bars(pos.ticker) self.broker.set_timestamp(bars.timestamp[bar]) return self.broker.close_position(pos, bars.open[bar], bar) def exit_at_limit(self, bar, price, pos): bars = self._get_bars(pos.ticker) self.broker.set_timestamp(bars.timestamp[bar]) if pos.is_long(): if bars.high[bar] >= price: if bars.open[bar] < price: return self.broker.close_position(pos, price, bar) else: return self.broker.close_position(pos, bars.open[bar], bar) else: return False else: if bars.low[bar] <= price: if bars.open[bar] > price: return self.broker.close_position(pos, price, bar) else: return self.broker.close_position(pos, bars.open[bar], bar) else: return False def exit_at_stop(self, bar, price, pos): bars = self._get_bars(pos.ticker) self.broker.set_timestamp(bars.timestamp[bar]) if pos.is_long(): if bars.low[bar] <= price: if bars.open[bar] > price: return self.broker.close_position(pos, price, bar) else: return self.broker.close_position(pos, bars.open[bar], bar) else: return False else: if bars.high[bar] >= price: if bars.open[bar] < price: return self.broker.close_position(pos, price, bar) else: return self.broker.close_position(pos, bars.open[bar], bar) else: return False def exit_at_close(self, bar, pos): bars = self._get_bars(pos.ticker) self.broker.set_timestamp(bars.timestamp[bar]) return self.broker.close_position(pos, bars.close[bar], bar)