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

8
src/naiback/broker/broker.py

@ -18,22 +18,22 @@ class Broker: @@ -18,22 +18,22 @@ class Broker:
def cash(self):
return self.cash_
def add_position(self, ticker, price, amount):
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)
pos.enter(price, amount, bar=bar_index)
self.cash_ -= price * amount
self.cash_ -= volume * 0.01 * self.commission_percentage
self.positions.append(pos)
return pos
def close_position(self, pos, price):
def close_position(self, pos, price, bar_index):
volume = abs(price * pos.size())
size = pos.size()
pos.exit(price)
pos.exit(price, bar=bar_index)
self.cash_ += price * size
self.cash_ -= volume * 0.01 * self.commission_percentage

5
src/naiback/broker/position.py

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

1
src/naiback/data/__init__.py

@ -0,0 +1 @@ @@ -0,0 +1 @@

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

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

3
src/naiback/indicators/__init__.py

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

49
src/naiback/strategy/strategy.py

@ -10,8 +10,8 @@ class Strategy: @@ -10,8 +10,8 @@ class Strategy:
def __init__(self):
self.feeds = []
self.all_bars = []
self.all_positions = []
self.broker = Broker()
self.bars = None
def add_feed(self, feed):
"""
@ -33,6 +33,9 @@ class Strategy: @@ -33,6 +33,9 @@ class Strategy:
self._prepare_bars()
self.execute()
def set_current_ticker(self, ticker):
self.bars = self._get_bars(ticker)
def _prepare_bars(self):
if len(self.feeds) == 0:
raise NaibackException('No feeds added to strategy')
@ -83,15 +86,15 @@ class Strategy: @@ -83,15 +86,15 @@ class Strategy:
def buy_at_open(self, bar, 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):
bars = self._get_bars(ticker)
if bars.low[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:
return self.broker.add_position(ticker, bars.open[bar], 1)
return self.broker.add_position(ticker, bars.open[bar], 1, bar)
else:
return None
@ -99,27 +102,27 @@ class Strategy: @@ -99,27 +102,27 @@ class Strategy:
bars = self._get_bars(ticker)
if bars.high[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:
return self.broker.add_position(ticker, bars.open[bar], 1)
return self.broker.add_position(ticker, bars.open[bar], 1, bar)
else:
return None
def buy_at_close(self, bar, 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):
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):
bars = self._get_bars(ticker)
if bars.high[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:
return self.broker.add_position(ticker, bars.open[bar], -1)
return self.broker.add_position(ticker, bars.open[bar], -1, bar)
else:
return None
@ -127,36 +130,36 @@ class Strategy: @@ -127,36 +130,36 @@ class Strategy:
bars = self._get_bars(ticker)
if bars.low[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:
return self.broker.add_position(ticker, bars.open[bar], -1)
return self.broker.add_position(ticker, bars.open[bar], -1, bar)
else:
return None
def short_at_close(self, bar, 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):
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):
bars = self._get_bars(pos.ticker)
if pos.is_long():
if bars.high[bar] >= price:
if bars.open[bar] < price:
return self.broker.close_position(pos, price)
return self.broker.close_position(pos, price, bar)
else:
return self.broker.close_position(pos, bars.open[bar])
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)
return self.broker.close_position(pos, price, bar)
else:
return self.broker.close_position(pos, bars.open[bar])
return self.broker.close_position(pos, bars.open[bar], bar)
else:
return False
@ -165,21 +168,21 @@ class Strategy: @@ -165,21 +168,21 @@ class Strategy:
if pos.is_long():
if bars.low[bar] <= price:
if bars.open[bar] > price:
return self.broker.close_position(pos, price)
return self.broker.close_position(pos, price, bar)
else:
return self.broker.close_position(pos, bars.open[bar])
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)
return self.broker.close_position(pos, price, bar)
else:
return self.broker.close_position(pos, bars.open[bar])
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)
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(): @@ -12,7 +12,7 @@ def test_broker_cash():
def test_broker_add_position_enough_cash():
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.size() == 1
@ -20,7 +20,7 @@ def test_broker_add_position_enough_cash(): @@ -20,7 +20,7 @@ def test_broker_add_position_enough_cash():
def test_broker_add_position_not_enough_cash():
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
@ -28,7 +28,7 @@ def test_broker_percentage_commissions(): @@ -28,7 +28,7 @@ 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)
pos = broker.add_position('FOO', price=10, amount=1, bar_index=0)
should_be_cash = 100 - 10 - 10 * 0.01 * 0.05
@ -37,15 +37,15 @@ def test_broker_percentage_commissions(): @@ -37,15 +37,15 @@ def test_broker_percentage_commissions():
def test_broker_all_position():
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()
def test_broker_close_position():
broker = Broker(initial_cash=100)
pos = broker.add_position('FOO', price=10, amount=1)
broker.close_position(pos, price=12)
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
@ -54,8 +54,8 @@ def test_broker_close_position_with_commission(): @@ -54,8 +54,8 @@ def test_broker_close_position_with_commission():
broker.set_commission(percentage=1) # 1%
pos = broker.add_position('FOO', price=10, amount=1)
broker.close_position(pos, price=12)
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

Loading…
Cancel
Save