Browse Source

Analyzers

master
Denis Tereshkin 7 years ago
parent
commit
bcc4a48525
  1. 2
      examples/multiple_assets.py
  2. 3
      src/naiback/analyzers/analyzer.py
  3. 5
      src/naiback/analyzers/statsanalyzer.py
  4. 16
      src/naiback/analyzers/tradeslistanalyzer.py
  5. 10
      src/naiback/data/bars.py
  6. 31
      src/naiback/strategy/strategy.py
  7. 101
      tests/test_strategy.py

2
examples/multiple_assets.py

@ -13,7 +13,7 @@ class MyStrategy(Strategy):
rsi1 = RSI(self.bars.close, 2) rsi1 = RSI(self.bars.close, 2)
self.set_current_ticker('GAZP') self.set_current_ticker('GAZP')
rsi2 = RSI(self.bars.close, 2) rsi2 = RSI(self.bars.close, 2)
for i in self.bars.index[200:]: for i in self.bars.index[200:-1]:
if self.last_position_is_active(): if self.last_position_is_active():
if i - self.last_position().entry_bar() > 3: if i - self.last_position().entry_bar() > 3:
for position in self.all_positions(): for position in self.all_positions():

3
src/naiback/analyzers/analyzer.py

@ -7,3 +7,6 @@ class Analyzer:
def generate_plain_text(self): def generate_plain_text(self):
pass pass
def get_result(self):
pass

5
src/naiback/analyzers/statsanalyzer.py

@ -39,6 +39,11 @@ class StatsAnalyzer(Analyzer):
return table.get_string() return table.get_string()
def get_result(self):
positions = self.strategy.broker.retired_positions() # TODO also add open positions
stats = self.calc_stats(positions)
return stats
def calc_stats(self, positions): def calc_stats(self, positions):
longs = list(filter(lambda x: x.is_long(), positions)) longs = list(filter(lambda x: x.is_long(), positions))
shorts = list(filter(lambda x: x.is_short(), positions)) shorts = list(filter(lambda x: x.is_short(), positions))

16
src/naiback/analyzers/tradeslistanalyzer.py

@ -0,0 +1,16 @@
from .analyzer import Analyzer
class TradesListAnalyzer(Analyzer):
def __init__(self, strategy):
self.strategy = strategy
def get_result(self):
positions = self.strategy.broker.retired_positions()
return [self.make_trade(pos) for pos in positions]
def make_trade(self, pos):
return { 'entry_price' : pos.entry_price(),
'exit_price' : pos.exit_price(),
'pnl' : pos.pnl() }

10
src/naiback/data/bars.py

@ -45,3 +45,13 @@ class Bars:
for bar in feed.items(): for bar in feed.items():
bars.append_bar(bar.open, bar.high, bar.low, bar.close, bar.volume, bar.timestamp) bars.append_bar(bar.open, bar.high, bar.low, bar.close, bar.volume, bar.timestamp)
return bars return bars
@classmethod
def from_feed_filter(cls, feed, from_time, to_time):
if feed.type() != 'bars':
raise NaibackException('Invalid feed type: "{}", should be "bars"'.format(feed.type()))
bars = Bars(feed.ticker())
for bar in feed.items():
if bar.timestamp >= from_time and bar.timestamp <= to_time:
bars.append_bar(bar.open, bar.high, bar.low, bar.close, bar.volume, bar.timestamp)
return bars

31
src/naiback/strategy/strategy.py

@ -3,6 +3,7 @@ from naiback.broker.position import Position
from naiback.broker.broker import Broker from naiback.broker.broker import Broker
from naiback.data.bars import Bars from naiback.data.bars import Bars
from naiback.analyzers.statsanalyzer import StatsAnalyzer from naiback.analyzers.statsanalyzer import StatsAnalyzer
from naiback.analyzers.tradeslistanalyzer import TradesListAnalyzer
class Strategy: class Strategy:
""" """
@ -13,10 +14,11 @@ class Strategy:
self.all_bars = [] self.all_bars = []
self.broker = Broker() self.broker = Broker()
self.bars = None self.bars = None
self.analyzer = StatsAnalyzer(self) self.analyzers = { 'stats' : StatsAnalyzer(self),
'tradeslist' : TradesListAnalyzer(self) }
def get_analyzer(self, analyzer_id): def get_analyzer(self, analyzer_id):
return self.analyzer return self.analyzers[analyzer_id]
def add_feed(self, feed): def add_feed(self, feed):
""" """
@ -35,19 +37,22 @@ class Strategy:
""" """
By default, just calls execute. By default, just calls execute.
""" """
self._prepare_bars() self._prepare_bars(from_time, to_time)
self.execute() self.execute()
def set_current_ticker(self, ticker): def set_current_ticker(self, ticker):
self.bars = self._get_bars(ticker) self.bars = self._get_bars(ticker)
def _prepare_bars(self): def _prepare_bars(self, from_time, to_time):
if len(self.feeds) == 0: if len(self.feeds) == 0:
raise NaibackException('No feeds added to strategy') raise NaibackException('No feeds added to strategy')
self.all_bars.clear() self.all_bars.clear()
for feed in self.feeds: for feed in self.feeds:
self.all_bars.append(Bars.from_feed(feed)) 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())) all_dates = list(sorted(self._combine_dates()))
@ -90,10 +95,14 @@ class Strategy:
return dates return dates
def buy_at_open(self, bar, ticker): def buy_at_open(self, bar, ticker):
if isinstance(ticker, int):
ticker = self.all_bars[ticker].ticker
bars = self._get_bars(ticker) bars = self._get_bars(ticker)
return self.broker.add_position(ticker, bars.open[bar], 1, bar) return self.broker.add_position(ticker, bars.open[bar], 1, bar)
def buy_at_limit(self, bar, price, ticker): def buy_at_limit(self, bar, price, ticker):
if isinstance(ticker, int):
ticker = self.all_bars[ticker].ticker
bars = self._get_bars(ticker) bars = self._get_bars(ticker)
if bars.low[bar] <= price: if bars.low[bar] <= price:
if bars.open[bar] > price: if bars.open[bar] > price:
@ -104,6 +113,8 @@ class Strategy:
return None return None
def buy_at_stop(self, bar, price, ticker): def buy_at_stop(self, bar, price, ticker):
if isinstance(ticker, int):
ticker = self.all_bars[ticker].ticker
bars = self._get_bars(ticker) bars = self._get_bars(ticker)
if bars.high[bar] >= price: if bars.high[bar] >= price:
if bars.open[bar] < price: if bars.open[bar] < price:
@ -114,14 +125,20 @@ class Strategy:
return None return None
def buy_at_close(self, bar, ticker): def buy_at_close(self, bar, ticker):
if isinstance(ticker, int):
ticker = self.all_bars[ticker].ticker
bars = self._get_bars(ticker) bars = self._get_bars(ticker)
return self.broker.add_position(ticker, bars.close[bar], 1, bar) return self.broker.add_position(ticker, bars.close[bar], 1, bar)
def short_at_open(self, bar, ticker): def short_at_open(self, bar, ticker):
if isinstance(ticker, int):
ticker = self.all_bars[ticker].ticker
bars = self._get_bars(ticker) bars = self._get_bars(ticker)
return self.broker.add_position(ticker, bars.open[bar], -1, bar) return self.broker.add_position(ticker, bars.open[bar], -1, bar)
def short_at_limit(self, bar, price, ticker): def short_at_limit(self, bar, price, ticker):
if isinstance(ticker, int):
ticker = self.all_bars[ticker].ticker
bars = self._get_bars(ticker) bars = self._get_bars(ticker)
if bars.high[bar] >= price: if bars.high[bar] >= price:
if bars.open[bar] < price: if bars.open[bar] < price:
@ -132,6 +149,8 @@ class Strategy:
return None return None
def short_at_stop(self, bar, price, ticker): def short_at_stop(self, bar, price, ticker):
if isinstance(ticker, int):
ticker = self.all_bars[ticker].ticker
bars = self._get_bars(ticker) bars = self._get_bars(ticker)
if bars.low[bar] <= price: if bars.low[bar] <= price:
if bars.open[bar] > price: if bars.open[bar] > price:
@ -142,6 +161,8 @@ class Strategy:
return None return None
def short_at_close(self, bar, ticker): def short_at_close(self, bar, ticker):
if isinstance(ticker, int):
ticker = self.all_bars[ticker].ticker
bars = self._get_bars(ticker) bars = self._get_bars(ticker)
return self.broker.add_position(ticker, bars.close[bar], -1, bar) return self.broker.add_position(ticker, bars.close[bar], -1, bar)

101
tests/test_strategy.py

@ -20,74 +20,80 @@ MICEX,D,20100114,000000,1439.5500000,1456.2700000,1439.5500000,1455.6500000,4437
class BuyAndSell(Strategy): class BuyAndSell(Strategy):
def __init__(self, buy_bar, sell_bar): def __init__(self, buy_bar, sell_bar, ticker='MICEX'):
super().__init__() super().__init__()
self.buy_bar = buy_bar self.buy_bar = buy_bar
self.sell_bar = sell_bar self.sell_bar = sell_bar
self.ticker = ticker
def execute(self): def execute(self):
pos = self.buy_at_open(self.buy_bar, 'MICEX') pos = self.buy_at_open(self.buy_bar, self.ticker)
self.exit_at_close(self.sell_bar, pos) self.exit_at_close(self.sell_bar, pos)
class BuyAndSellLimit(Strategy): class BuyAndSellLimit(Strategy):
def __init__(self, buy_bar, buy_price, sell_bar, sell_price): def __init__(self, buy_bar, buy_price, sell_bar, sell_price, ticker='MICEX'):
super().__init__() super().__init__()
self.buy_bar = buy_bar self.buy_bar = buy_bar
self.buy_price = buy_price self.buy_price = buy_price
self.sell_bar = sell_bar self.sell_bar = sell_bar
self.sell_price = sell_price self.sell_price = sell_price
self.ticker = ticker
def execute(self): def execute(self):
pos = self.buy_at_limit(self.buy_bar, self.buy_price, 'MICEX') pos = self.buy_at_limit(self.buy_bar, self.buy_price, self.ticker)
self.exit_at_limit(self.sell_bar, self.sell_price, pos) self.exit_at_limit(self.sell_bar, self.sell_price, pos)
class BuyOpenAndSellStop(Strategy): class BuyOpenAndSellStop(Strategy):
def __init__(self, buy_bar, sell_bar, sell_price): def __init__(self, buy_bar, sell_bar, sell_price, ticker='MICEX'):
super().__init__() super().__init__()
self.buy_bar = buy_bar self.buy_bar = buy_bar
self.sell_bar = sell_bar self.sell_bar = sell_bar
self.sell_price = sell_price self.sell_price = sell_price
self.ticker = ticker
def execute(self): def execute(self):
pos = self.buy_at_open(self.buy_bar, 'MICEX') pos = self.buy_at_open(self.buy_bar, self.ticker)
self.exit_at_stop(self.sell_bar, self.sell_price, pos) self.exit_at_stop(self.sell_bar, self.sell_price, pos)
class ShortAndCover(Strategy): class ShortAndCover(Strategy):
def __init__(self, short_bar, cover_bar): def __init__(self, short_bar, cover_bar, ticker='MICEX'):
super().__init__() super().__init__()
self.short_bar = short_bar self.short_bar = short_bar
self.cover_bar = cover_bar self.cover_bar = cover_bar
self.ticker = ticker
def execute(self): def execute(self):
pos = self.short_at_open(self.short_bar, 'MICEX') pos = self.short_at_open(self.short_bar, self.ticker)
self.exit_at_close(self.cover_bar, pos) self.exit_at_close(self.cover_bar, pos)
class ShortAndCoverLimit(Strategy): class ShortAndCoverLimit(Strategy):
def __init__(self, short_bar, short_price, cover_bar, cover_price): def __init__(self, short_bar, short_price, cover_bar, cover_price, ticker='MICEX'):
super().__init__() super().__init__()
self.short_bar = short_bar self.short_bar = short_bar
self.short_price = short_price self.short_price = short_price
self.cover_bar = cover_bar self.cover_bar = cover_bar
self.cover_price = cover_price self.cover_price = cover_price
self.ticker = ticker
def execute(self): def execute(self):
pos = self.short_at_limit(self.short_bar, self.short_price, 'MICEX') pos = self.short_at_limit(self.short_bar, self.short_price, self.ticker)
self.exit_at_limit(self.cover_bar, self.cover_price, pos) self.exit_at_limit(self.cover_bar, self.cover_price, pos)
class ShortOpenAndCoverStop(Strategy): class ShortOpenAndCoverStop(Strategy):
def __init__(self, short_bar, cover_bar, cover_price): def __init__(self, short_bar, cover_bar, cover_price, ticker='MICEX'):
super().__init__() super().__init__()
self.short_bar = short_bar self.short_bar = short_bar
self.cover_bar = cover_bar self.cover_bar = cover_bar
self.cover_price = cover_price self.cover_price = cover_price
self.ticker = ticker
def execute(self): def execute(self):
pos = self.short_at_open(self.short_bar, 'MICEX') pos = self.short_at_open(self.short_bar, self.ticker)
self.exit_at_stop(self.cover_bar, self.cover_price, pos) self.exit_at_stop(self.cover_bar, self.cover_price, pos)
def test_buy_and_sell_1(feed): def test_buy_and_sell_1(feed):
@ -123,6 +129,17 @@ def test_buy_and_sell_3(feed):
ending_cash = s.broker.cash() ending_cash = s.broker.cash()
assert(ending_cash == (initial_cash + 1435.01 - 1444.78)) assert(ending_cash == (initial_cash + 1435.01 - 1444.78))
def test_buy_and_sell_1_index(feed):
s = BuyAndSell(0, 0, 0)
s.add_feed(feed)
initial_cash = s.broker.cash()
s.run()
ending_cash = s.broker.cash()
assert(ending_cash == (initial_cash + 1444.78 - 1411.37))
def test_buy_and_sell_limit_1(feed): def test_buy_and_sell_limit_1(feed):
s = BuyAndSellLimit(0, 1412, 1, 1445) s = BuyAndSellLimit(0, 1412, 1, 1445)
s.add_feed(feed) s.add_feed(feed)
@ -159,6 +176,18 @@ def test_buy_and_sell_limit_3(feed):
assert(ending_cash == (initial_cash + 1417.80 - 1444.78)) assert(ending_cash == (initial_cash + 1417.80 - 1444.78))
assert(not s.last_position_is_active()) assert(not s.last_position_is_active())
def test_buy_and_sell_limit_1_index(feed):
s = BuyAndSellLimit(0, 1412, 1, 1445, 0)
s.add_feed(feed)
initial_cash = s.broker.cash()
s.run()
ending_cash = s.broker.cash()
assert(ending_cash == (initial_cash + 1445 - 1411.37))
assert(not s.last_position_is_active())
def test_buy_and_sell_stop_1(feed): def test_buy_and_sell_stop_1(feed):
s = BuyOpenAndSellStop(0, 1, 1430) s = BuyOpenAndSellStop(0, 1, 1430)
s.add_feed(feed) s.add_feed(feed)
@ -183,6 +212,18 @@ def test_buy_and_sell_stop_2(feed):
assert(ending_cash == (initial_cash + 1444.78 - 1411.37)) assert(ending_cash == (initial_cash + 1444.78 - 1411.37))
assert(not s.last_position_is_active()) assert(not s.last_position_is_active())
def test_buy_and_sell_stop_1_index(feed):
s = BuyOpenAndSellStop(0, 1, 1430, 0)
s.add_feed(feed)
initial_cash = s.broker.cash()
s.run()
ending_cash = s.broker.cash()
assert(ending_cash == (initial_cash + 1430 - 1411.37))
assert(not s.last_position_is_active())
def test_short_and_cover_1(feed): def test_short_and_cover_1(feed):
s = ShortAndCover(0, 0) s = ShortAndCover(0, 0)
s.add_feed(feed) s.add_feed(feed)
@ -205,6 +246,17 @@ def test_short_and_cover_2(feed):
ending_cash = s.broker.cash() ending_cash = s.broker.cash()
assert(ending_cash == (initial_cash + 1411.37 - 1427.67)) assert(ending_cash == (initial_cash + 1411.37 - 1427.67))
def test_short_and_cover_1_index(feed):
s = ShortAndCover(0, 0, 0)
s.add_feed(feed)
initial_cash = s.broker.cash()
s.run()
ending_cash = s.broker.cash()
assert(ending_cash == (initial_cash + 1411.37 - 1444.78))
def test_short_and_cover_limit_1(feed): def test_short_and_cover_limit_1(feed):
s = ShortAndCoverLimit(0, 1450, 1, 1430) s = ShortAndCoverLimit(0, 1450, 1, 1430)
s.add_feed(feed) s.add_feed(feed)
@ -244,6 +296,19 @@ def test_short_and_cover_limit_3(feed):
assert(ending_cash == (initial_cash + 1430 - 1444.78)) assert(ending_cash == (initial_cash + 1430 - 1444.78))
assert(not s.last_position_is_active()) assert(not s.last_position_is_active())
def test_short_and_cover_limit_1_index(feed):
s = ShortAndCoverLimit(0, 1450, 1, 1430, 0)
s.add_feed(feed)
initial_cash = s.broker.cash()
s.run()
ending_cash = s.broker.cash()
assert(ending_cash == (initial_cash + 1450 - 1430))
assert(not s.last_position_is_active())
def test_short_and_cover_stop_1(feed): def test_short_and_cover_stop_1(feed):
s = ShortOpenAndCoverStop(0, 1, 1445) s = ShortOpenAndCoverStop(0, 1, 1445)
s.add_feed(feed) s.add_feed(feed)
@ -268,3 +333,15 @@ def test_short_and_cover_stop_2(feed):
assert(ending_cash == (initial_cash + 1411.37 - 1444.78)) assert(ending_cash == (initial_cash + 1411.37 - 1444.78))
assert(not s.last_position_is_active()) assert(not s.last_position_is_active())
def test_short_and_cover_stop_1_index(feed):
s = ShortOpenAndCoverStop(0, 1, 1445)
s.add_feed(feed)
initial_cash = s.broker.cash()
s.run()
ending_cash = s.broker.cash()
assert(ending_cash == (initial_cash + 1411.37 - 1445))
assert(not s.last_position_is_active())

Loading…
Cancel
Save