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. 29
      src/naiback/strategy/strategy.py
  7. 101
      tests/test_strategy.py

2
examples/multiple_assets.py

@ -13,7 +13,7 @@ class MyStrategy(Strategy): @@ -13,7 +13,7 @@ class MyStrategy(Strategy):
rsi1 = RSI(self.bars.close, 2)
self.set_current_ticker('GAZP')
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 i - self.last_position().entry_bar() > 3:
for position in self.all_positions():

3
src/naiback/analyzers/analyzer.py

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

5
src/naiback/analyzers/statsanalyzer.py

@ -39,6 +39,11 @@ class StatsAnalyzer(Analyzer): @@ -39,6 +39,11 @@ class StatsAnalyzer(Analyzer):
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):
longs = list(filter(lambda x: x.is_long(), positions))
shorts = list(filter(lambda x: x.is_short(), positions))

16
src/naiback/analyzers/tradeslistanalyzer.py

@ -0,0 +1,16 @@ @@ -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: @@ -45,3 +45,13 @@ class Bars:
for bar in feed.items():
bars.append_bar(bar.open, bar.high, bar.low, bar.close, bar.volume, bar.timestamp)
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

29
src/naiback/strategy/strategy.py

@ -3,6 +3,7 @@ from naiback.broker.position import Position @@ -3,6 +3,7 @@ from naiback.broker.position import Position
from naiback.broker.broker import Broker
from naiback.data.bars import Bars
from naiback.analyzers.statsanalyzer import StatsAnalyzer
from naiback.analyzers.tradeslistanalyzer import TradesListAnalyzer
class Strategy:
"""
@ -13,10 +14,11 @@ class Strategy: @@ -13,10 +14,11 @@ class Strategy:
self.all_bars = []
self.broker = Broker()
self.bars = None
self.analyzer = StatsAnalyzer(self)
self.analyzers = { 'stats' : StatsAnalyzer(self),
'tradeslist' : TradesListAnalyzer(self) }
def get_analyzer(self, analyzer_id):
return self.analyzer
return self.analyzers[analyzer_id]
def add_feed(self, feed):
"""
@ -35,19 +37,22 @@ class Strategy: @@ -35,19 +37,22 @@ class Strategy:
"""
By default, just calls execute.
"""
self._prepare_bars()
self._prepare_bars(from_time, to_time)
self.execute()
def set_current_ticker(self, ticker):
self.bars = self._get_bars(ticker)
def _prepare_bars(self):
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()))
@ -90,10 +95,14 @@ class Strategy: @@ -90,10 +95,14 @@ class Strategy:
return dates
def buy_at_open(self, bar, ticker):
if isinstance(ticker, int):
ticker = self.all_bars[ticker].ticker
bars = self._get_bars(ticker)
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)
if bars.low[bar] <= price:
if bars.open[bar] > price:
@ -104,6 +113,8 @@ class Strategy: @@ -104,6 +113,8 @@ class Strategy:
return None
def buy_at_stop(self, bar, price, ticker):
if isinstance(ticker, int):
ticker = self.all_bars[ticker].ticker
bars = self._get_bars(ticker)
if bars.high[bar] >= price:
if bars.open[bar] < price:
@ -114,14 +125,20 @@ class Strategy: @@ -114,14 +125,20 @@ class Strategy:
return None
def buy_at_close(self, bar, ticker):
if isinstance(ticker, int):
ticker = self.all_bars[ticker].ticker
bars = self._get_bars(ticker)
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)
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)
if bars.high[bar] >= price:
if bars.open[bar] < price:
@ -132,6 +149,8 @@ class Strategy: @@ -132,6 +149,8 @@ class Strategy:
return None
def short_at_stop(self, bar, price, ticker):
if isinstance(ticker, int):
ticker = self.all_bars[ticker].ticker
bars = self._get_bars(ticker)
if bars.low[bar] <= price:
if bars.open[bar] > price:
@ -142,6 +161,8 @@ class Strategy: @@ -142,6 +161,8 @@ class Strategy:
return None
def short_at_close(self, bar, ticker):
if isinstance(ticker, int):
ticker = self.all_bars[ticker].ticker
bars = self._get_bars(ticker)
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 @@ -20,74 +20,80 @@ MICEX,D,20100114,000000,1439.5500000,1456.2700000,1439.5500000,1455.6500000,4437
class BuyAndSell(Strategy):
def __init__(self, buy_bar, sell_bar):
def __init__(self, buy_bar, sell_bar, ticker='MICEX'):
super().__init__()
self.buy_bar = buy_bar
self.sell_bar = sell_bar
self.ticker = ticker
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)
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__()
self.buy_bar = buy_bar
self.buy_price = buy_price
self.sell_bar = sell_bar
self.sell_price = sell_price
self.ticker = ticker
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)
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__()
self.buy_bar = buy_bar
self.sell_bar = sell_bar
self.sell_price = sell_price
self.ticker = ticker
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)
class ShortAndCover(Strategy):
def __init__(self, short_bar, cover_bar):
def __init__(self, short_bar, cover_bar, ticker='MICEX'):
super().__init__()
self.short_bar = short_bar
self.cover_bar = cover_bar
self.ticker = ticker
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)
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__()
self.short_bar = short_bar
self.short_price = short_price
self.cover_bar = cover_bar
self.cover_price = cover_price
self.ticker = ticker
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)
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__()
self.short_bar = short_bar
self.cover_bar = cover_bar
self.cover_price = cover_price
self.ticker = ticker
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)
def test_buy_and_sell_1(feed):
@ -123,6 +129,17 @@ def test_buy_and_sell_3(feed): @@ -123,6 +129,17 @@ def test_buy_and_sell_3(feed):
ending_cash = s.broker.cash()
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):
s = BuyAndSellLimit(0, 1412, 1, 1445)
s.add_feed(feed)
@ -159,6 +176,18 @@ def test_buy_and_sell_limit_3(feed): @@ -159,6 +176,18 @@ def test_buy_and_sell_limit_3(feed):
assert(ending_cash == (initial_cash + 1417.80 - 1444.78))
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):
s = BuyOpenAndSellStop(0, 1, 1430)
s.add_feed(feed)
@ -183,6 +212,18 @@ def test_buy_and_sell_stop_2(feed): @@ -183,6 +212,18 @@ def test_buy_and_sell_stop_2(feed):
assert(ending_cash == (initial_cash + 1444.78 - 1411.37))
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):
s = ShortAndCover(0, 0)
s.add_feed(feed)
@ -205,6 +246,17 @@ def test_short_and_cover_2(feed): @@ -205,6 +246,17 @@ def test_short_and_cover_2(feed):
ending_cash = s.broker.cash()
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):
s = ShortAndCoverLimit(0, 1450, 1, 1430)
s.add_feed(feed)
@ -244,6 +296,19 @@ def test_short_and_cover_limit_3(feed): @@ -244,6 +296,19 @@ def test_short_and_cover_limit_3(feed):
assert(ending_cash == (initial_cash + 1430 - 1444.78))
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):
s = ShortOpenAndCoverStop(0, 1, 1445)
s.add_feed(feed)
@ -268,3 +333,15 @@ def test_short_and_cover_stop_2(feed): @@ -268,3 +333,15 @@ def test_short_and_cover_stop_2(feed):
assert(ending_cash == (initial_cash + 1411.37 - 1444.78))
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