Browse Source

Some API changes, test data

master
Denis Tereshkin 8 years ago
parent
commit
0b0d2f19da
  1. 2006
      examples/data/GAZP_20100101_20171231_daily.csv
  2. 2006
      examples/data/SBER_20100101_20171231_daily.csv
  3. 19
      examples/multiple_assets.py
  4. 8
      src/naiback/broker/broker.py
  5. 5
      src/naiback/broker/position.py
  6. 1
      src/naiback/data/__init__.py
  7. 3
      src/naiback/data/feeds/__init__.py
  8. 3
      src/naiback/indicators/__init__.py
  9. 49
      src/naiback/strategy/strategy.py
  10. 16
      tests/test_broker.py

2006
examples/data/GAZP_20100101_20171231_daily.csv

File diff suppressed because it is too large Load Diff

2006
examples/data/SBER_20100101_20171231_daily.csv

File diff suppressed because it is too large Load Diff

19
examples/multiple_assets.py

@ -1,7 +1,7 @@
from naiback.strategy import Strategy from naiback.strategy import Strategy
from naiback.data.feeds import GenericCSVFeed from naiback.data.feeds import GenericCSVFeed
from naiback.indicators import SMA, RSI from naiback.indicators import EMA, RSI
class MyStrategy(Strategy): class MyStrategy(Strategy):
@ -9,22 +9,23 @@ class MyStrategy(Strategy):
super().__init__() super().__init__()
def execute(self): def execute(self):
self.set_context('FOO') self.set_current_ticker('SBER')
rsi1 = RSI(self.bars.close, 2) rsi1 = RSI(self.bars.close, 2)
self.set_context('BAR') 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:]:
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():
position.exit_at_close(i) self.exit_at_close(i, position)
else: else:
if rsi1[i] < 20 and rsi2[i] > 80: if rsi1[i] < 20 and rsi2[i] > 80:
self.buy_at_open(i + 1, 'FOO') self.buy_at_open(i + 1, 'SBER')
self.short_at_open(i + 1, 'BAR') self.short_at_open(i + 1, 'GAZP')
if __name__ == "__main__": if __name__ == "__main__":
strategy = MyStrategy() strategy = MyStrategy()
strategy.add_feed(FinamCSVFeed('data/SBER_20100101_20161231_daily.csv')) strategy.add_feed(GenericCSVFeed(open('data/SBER_20100101_20171231_daily.csv', 'r')))
strategy.run(from_time='2012-01-01', to_time='2016-12-31') strategy.add_feed(GenericCSVFeed(open('data/GAZP_20100101_20171231_daily.csv', 'r')))
strategy.run(from_time='2012-01-01', to_time='2017-12-31')
print(strategy.get_analyzer('stats').generate_plain_text()) print(strategy.get_analyzer('stats').generate_plain_text())

8
src/naiback/broker/broker.py

@ -18,22 +18,22 @@ class Broker:
def cash(self): def cash(self):
return self.cash_ return self.cash_
def add_position(self, ticker, price, amount): def add_position(self, ticker, price, amount, bar_index):
volume = abs(price * amount) volume = abs(price * amount)
if amount > 0: if amount > 0:
if volume * (1 + 0.01 * self.commission_percentage) > self.cash_: if volume * (1 + 0.01 * self.commission_percentage) > self.cash_:
return None return None
pos = Position(ticker) pos = Position(ticker)
pos.enter(price, amount) pos.enter(price, amount, bar=bar_index)
self.cash_ -= price * amount self.cash_ -= price * amount
self.cash_ -= volume * 0.01 * self.commission_percentage self.cash_ -= volume * 0.01 * self.commission_percentage
self.positions.append(pos) self.positions.append(pos)
return pos return pos
def close_position(self, pos, price): def close_position(self, pos, price, bar_index):
volume = abs(price * pos.size()) volume = abs(price * pos.size())
size = pos.size() size = pos.size()
pos.exit(price) pos.exit(price, bar=bar_index)
self.cash_ += price * size self.cash_ += price * size
self.cash_ -= volume * 0.01 * self.commission_percentage self.cash_ -= volume * 0.01 * self.commission_percentage

5
src/naiback/broker/position.py

@ -38,9 +38,12 @@ class Position:
for k, v in kwargs.items(): for k, v in kwargs.items():
self.entry_metadata[k] = v self.entry_metadata[k] = v
def exit(self, price): def exit(self, price, **kwargs):
self.exit_price_ = price self.exit_price_ = price
self.total_pnl += (self.exit_price() - self.entry_price()) * self.size() self.total_pnl += (self.exit_price() - self.entry_price()) * self.size()
self.size_ = 0 self.size_ = 0
for k, v in kwargs.items():
self.exit_metadata[k] = v

1
src/naiback/data/__init__.py

@ -0,0 +1 @@

3
src/naiback/data/feeds/__init__.py

@ -0,0 +1,3 @@
from .genericcsvfeed import GenericCSVFeed

3
src/naiback/indicators/__init__.py

@ -0,0 +1,3 @@
from .ema import EMA
from .rsi import RSI

49
src/naiback/strategy/strategy.py

@ -10,8 +10,8 @@ class Strategy:
def __init__(self): def __init__(self):
self.feeds = [] self.feeds = []
self.all_bars = [] self.all_bars = []
self.all_positions = []
self.broker = Broker() self.broker = Broker()
self.bars = None
def add_feed(self, feed): def add_feed(self, feed):
""" """
@ -33,6 +33,9 @@ class Strategy:
self._prepare_bars() self._prepare_bars()
self.execute() self.execute()
def set_current_ticker(self, ticker):
self.bars = self._get_bars(ticker)
def _prepare_bars(self): def _prepare_bars(self):
if len(self.feeds) == 0: if len(self.feeds) == 0:
raise NaibackException('No feeds added to strategy') raise NaibackException('No feeds added to strategy')
@ -83,15 +86,15 @@ class Strategy:
def buy_at_open(self, bar, ticker): def buy_at_open(self, bar, ticker):
bars = self._get_bars(ticker) bars = self._get_bars(ticker)
return self.broker.add_position(ticker, bars.open[bar], 1) 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):
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:
return self.broker.add_position(ticker, price, 1) return self.broker.add_position(ticker, price, 1, bar)
else: else:
return self.broker.add_position(ticker, bars.open[bar], 1) return self.broker.add_position(ticker, bars.open[bar], 1, bar)
else: else:
return None return None
@ -99,27 +102,27 @@ class Strategy:
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:
return self.broker.add_position(ticker, price, 1) return self.broker.add_position(ticker, price, 1, bar)
else: else:
return self.broker.add_position(ticker, bars.open[bar], 1) return self.broker.add_position(ticker, bars.open[bar], 1, bar)
else: else:
return None return None
def buy_at_close(self, bar, ticker): def buy_at_close(self, bar, ticker):
bars = self._get_bars(ticker) bars = self._get_bars(ticker)
return self.broker.add_position(ticker, bars.close[bar], 1) 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):
bars = self._get_bars(ticker) bars = self._get_bars(ticker)
return self.broker.add_position(ticker, bars.open[bar], -1) 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):
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:
return self.broker.add_position(ticker, price, -1) return self.broker.add_position(ticker, price, -1, bar)
else: else:
return self.broker.add_position(ticker, bars.open[bar], -1) return self.broker.add_position(ticker, bars.open[bar], -1, bar)
else: else:
return None return None
@ -127,36 +130,36 @@ class Strategy:
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:
return self.broker.add_position(ticker, price, -1) return self.broker.add_position(ticker, price, -1, bar)
else: else:
return self.broker.add_position(ticker, bars.open[bar], -1) return self.broker.add_position(ticker, bars.open[bar], -1, bar)
else: else:
return None return None
def short_at_close(self, bar, ticker): def short_at_close(self, bar, ticker):
bars = self._get_bars(ticker) bars = self._get_bars(ticker)
return self.broker.add_position(ticker, bars.close[bar], -1) return self.broker.add_position(ticker, bars.close[bar], -1, bar)
def exit_at_open(self, bar, pos): def exit_at_open(self, bar, pos):
bars = self._get_bars(pos.ticker) bars = self._get_bars(pos.ticker)
return self.broker.close_position(pos, bars.open[bar]) return self.broker.close_position(pos, bars.open[bar], bar)
def exit_at_limit(self, bar, price, pos): def exit_at_limit(self, bar, price, pos):
bars = self._get_bars(pos.ticker) bars = self._get_bars(pos.ticker)
if pos.is_long(): if pos.is_long():
if bars.high[bar] >= price: if bars.high[bar] >= price:
if bars.open[bar] < price: if bars.open[bar] < price:
return self.broker.close_position(pos, price) return self.broker.close_position(pos, price, bar)
else: else:
return self.broker.close_position(pos, bars.open[bar]) return self.broker.close_position(pos, bars.open[bar], bar)
else: else:
return False return False
else: else:
if bars.low[bar] <= price: if bars.low[bar] <= price:
if bars.open[bar] > price: if bars.open[bar] > price:
return self.broker.close_position(pos, price) return self.broker.close_position(pos, price, bar)
else: else:
return self.broker.close_position(pos, bars.open[bar]) return self.broker.close_position(pos, bars.open[bar], bar)
else: else:
return False return False
@ -165,21 +168,21 @@ class Strategy:
if pos.is_long(): if pos.is_long():
if bars.low[bar] <= price: if bars.low[bar] <= price:
if bars.open[bar] > price: if bars.open[bar] > price:
return self.broker.close_position(pos, price) return self.broker.close_position(pos, price, bar)
else: else:
return self.broker.close_position(pos, bars.open[bar]) return self.broker.close_position(pos, bars.open[bar], bar)
else: else:
return False return False
else: else:
if bars.high[bar] >= price: if bars.high[bar] >= price:
if bars.open[bar] < price: if bars.open[bar] < price:
return self.broker.close_position(pos, price) return self.broker.close_position(pos, price, bar)
else: else:
return self.broker.close_position(pos, bars.open[bar]) return self.broker.close_position(pos, bars.open[bar], bar)
else: else:
return False return False
def exit_at_close(self, bar, pos): def exit_at_close(self, bar, pos):
bars = self._get_bars(pos.ticker) bars = self._get_bars(pos.ticker)
return self.broker.close_position(pos, bars.close[bar]) return self.broker.close_position(pos, bars.close[bar], bar)

16
tests/test_broker.py

@ -12,7 +12,7 @@ def test_broker_cash():
def test_broker_add_position_enough_cash(): def test_broker_add_position_enough_cash():
broker = Broker(initial_cash=100) broker = Broker(initial_cash=100)
pos = broker.add_position('FOO', price=10, amount=1) pos = broker.add_position('FOO', price=10, amount=1, bar_index=0)
assert pos.entry_price() == 10 assert pos.entry_price() == 10
assert pos.size() == 1 assert pos.size() == 1
@ -20,7 +20,7 @@ def test_broker_add_position_enough_cash():
def test_broker_add_position_not_enough_cash(): def test_broker_add_position_not_enough_cash():
broker = Broker(initial_cash=100) broker = Broker(initial_cash=100)
pos = broker.add_position('FOO', price=1000, amount=1) pos = broker.add_position('FOO', price=1000, amount=1, bar_index=0)
assert pos is None assert pos is None
@ -28,7 +28,7 @@ def test_broker_percentage_commissions():
broker = Broker(initial_cash=100) broker = Broker(initial_cash=100)
broker.set_commission(percentage=0.05) # 0.05% broker.set_commission(percentage=0.05) # 0.05%
pos = broker.add_position('FOO', price=10, amount=1) pos = broker.add_position('FOO', price=10, amount=1, bar_index=0)
should_be_cash = 100 - 10 - 10 * 0.01 * 0.05 should_be_cash = 100 - 10 - 10 * 0.01 * 0.05
@ -37,15 +37,15 @@ def test_broker_percentage_commissions():
def test_broker_all_position(): def test_broker_all_position():
broker = Broker(initial_cash=100) broker = Broker(initial_cash=100)
pos = broker.add_position('FOO', price=10, amount=1) pos = broker.add_position('FOO', price=10, amount=1, bar_index=0)
assert pos in broker.all_positions() assert pos in broker.all_positions()
def test_broker_close_position(): def test_broker_close_position():
broker = Broker(initial_cash=100) broker = Broker(initial_cash=100)
pos = broker.add_position('FOO', price=10, amount=1) pos = broker.add_position('FOO', price=10, amount=1, bar_index=0)
broker.close_position(pos, price=12) broker.close_position(pos, price=12, bar_index=1)
assert broker.cash() == 100 + 2 assert broker.cash() == 100 + 2
@ -54,8 +54,8 @@ def test_broker_close_position_with_commission():
broker.set_commission(percentage=1) # 1% broker.set_commission(percentage=1) # 1%
pos = broker.add_position('FOO', price=10, amount=1) pos = broker.add_position('FOO', price=10, amount=1, bar_index=0)
broker.close_position(pos, price=12) broker.close_position(pos, price=12, bar_index=1)
assert broker.cash() == 100 + 2 - (10 + 12) * 0.01 assert broker.cash() == 100 + 2 - (10 + 12) * 0.01

Loading…
Cancel
Save