From 1459f020d30009adea241e62c644a76493dc2176 Mon Sep 17 00:00:00 2001 From: Denis Tereshkin Date: Thu, 13 Dec 2018 16:41:08 +0700 Subject: [PATCH] Trades: entry & exit dates Now positions get new metadata: 'entry_time' and 'exit_time' which store datetime object of entry and exit bars --- src/naiback/analyzers/tradeslistanalyzer.py | 2 ++ src/naiback/broker/broker.py | 8 ++++++-- src/naiback/broker/position.py | 6 ++++++ src/naiback/strategy/strategy.py | 12 ++++++++++++ 4 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/naiback/analyzers/tradeslistanalyzer.py b/src/naiback/analyzers/tradeslistanalyzer.py index c4b49a8..fa27c00 100644 --- a/src/naiback/analyzers/tradeslistanalyzer.py +++ b/src/naiback/analyzers/tradeslistanalyzer.py @@ -13,4 +13,6 @@ class TradesListAnalyzer(Analyzer): def make_trade(self, pos): return { 'entry_price' : pos.entry_price(), 'exit_price' : pos.exit_price(), + 'entry_time' : pos.entry_time(), + 'exit_time' : pos.exit_time(), 'pnl' : pos.pnl() } diff --git a/src/naiback/broker/broker.py b/src/naiback/broker/broker.py index ba0a1c1..dc79f7a 100644 --- a/src/naiback/broker/broker.py +++ b/src/naiback/broker/broker.py @@ -15,17 +15,21 @@ class Broker: self.positions = [] self.retired_positions_ = [] self.commission_percentage = 0 + self.timestamp = None def cash(self): return self.cash_ + def set_timestamp(self, ts): + self.timestamp = ts + def add_position(self, ticker, price, amount, bar_index): volume = abs(price * amount) if amount > 0: if volume * (1 + 0.01 * self.commission_percentage) > self.cash_: return None pos = Position(ticker) - pos.enter(price, amount, bar=bar_index) + pos.enter(price, amount, bar=bar_index, timestamp=self.timestamp) self.cash_ -= price * amount self.cash_ -= volume * 0.01 * self.commission_percentage self.positions.append(pos) @@ -34,7 +38,7 @@ class Broker: def close_position(self, pos, price, bar_index): volume = abs(price * pos.size()) size = pos.size() - pos.exit(price, bar=bar_index) + pos.exit(price, bar=bar_index, timestamp=self.timestamp) self.retired_positions_.append(pos) self.positions.remove(pos) diff --git a/src/naiback/broker/position.py b/src/naiback/broker/position.py index 0e3a308..346b301 100644 --- a/src/naiback/broker/position.py +++ b/src/naiback/broker/position.py @@ -35,9 +35,15 @@ class Position: def entry_bar(self): return self.entry_metadata['bar'] + def entry_time(self): + return self.entry_metadata['timestamp'] + def exit_bar(self): return self.exit_metadata['bar'] + def exit_time(self): + return self.exit_metadata['timestamp'] + def bars_in_trade(self): return self.exit_bar() - self.entry_bar() diff --git a/src/naiback/strategy/strategy.py b/src/naiback/strategy/strategy.py index b23e450..4c7eb85 100644 --- a/src/naiback/strategy/strategy.py +++ b/src/naiback/strategy/strategy.py @@ -101,12 +101,14 @@ class Strategy: 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], 1, bar) def buy_at_limit(self, bar, price, ticker): 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, 1, bar) @@ -119,6 +121,7 @@ class Strategy: 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, 1, bar) @@ -131,18 +134,21 @@ class Strategy: 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], 1, bar) def short_at_open(self, bar, ticker): 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], -1, bar) def short_at_limit(self, bar, price, ticker): 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, -1, bar) @@ -155,6 +161,7 @@ class Strategy: 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, -1, bar) @@ -167,14 +174,17 @@ class Strategy: 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], -1, 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: @@ -194,6 +204,7 @@ class Strategy: 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: @@ -213,5 +224,6 @@ class Strategy: 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)