Browse Source

Some updates

master
Denis Tereshkin 5 years ago
parent
commit
145e059e3c
  1. 44
      src/naiback/analyzers/statsanalyzer.py
  2. 14
      src/naiback/broker/broker.py
  3. 31
      src/naiback/broker/position.py
  4. 35
      src/naiback/data/feeds/yahoofeed.py
  5. 4
      src/naiback/indicators/__init__.py
  6. 33
      src/naiback/indicators/adx.py
  7. 24
      src/naiback/indicators/atr.py
  8. 3
      src/naiback/indicators/bollinger.py
  9. 2
      src/naiback/indicators/ema.py
  10. 13
      src/naiback/indicators/smma.py

44
src/naiback/analyzers/statsanalyzer.py

@ -16,6 +16,25 @@ def render_ratio(a, b): @@ -16,6 +16,25 @@ def render_ratio(a, b):
else:
return 0
def calculate_kelly(pos):
winning = list(filter(lambda x: x.pnl() >= 0, pos))
losing = list(filter(lambda x: x.pnl() < 0, pos))
won = len(winning)
lost = len(losing)
if won == 0:
return 0
elif lost == 0:
return 1
avg_winning = sum(map(lambda x: x.pnl(), winning)) / won
avg_losing = sum(map(lambda x: x.pnl(), losing)) / lost
p = float(won) / (won + lost)
return p + (1 - p)/(avg_winning / avg_losing)
class StatsAnalyzer(Analyzer):
def __init__(self, strategy):
@ -57,6 +76,10 @@ class StatsAnalyzer(Analyzer): @@ -57,6 +76,10 @@ class StatsAnalyzer(Analyzer):
result['long']['net_profit'] = sum([pos.pnl() for pos in longs])
result['short']['net_profit'] = sum([pos.pnl() for pos in shorts])
result['all']['total_commission'] = sum([pos.total_commission() for pos in positions])
result['long']['total_commission'] = sum([pos.total_commission() for pos in longs])
result['short']['total_commission'] = sum([pos.total_commission() for pos in shorts])
result['all']['bars_in_trade'] = sum([pos.bars_in_trade() for pos in positions])
result['long']['bars_in_trade'] = sum([pos.bars_in_trade() for pos in longs])
result['short']['bars_in_trade'] = sum([pos.bars_in_trade() for pos in shorts])
@ -103,24 +126,27 @@ class StatsAnalyzer(Analyzer): @@ -103,24 +126,27 @@ class StatsAnalyzer(Analyzer):
mean = np.mean(list(map(lambda x: x.pnl(), positions)))
stddev = np.std(list(map(lambda x: x.pnl(), positions)))
sharpe = mean / stddev
tstat = sharpe * math.sqrt(len(positions))
result['all']['sharpe_ratio'] = sharpe
z_score = mean / stddev
tstat = z_score * math.sqrt(len(positions))
result['all']['z_score'] = z_score
result['all']['t_stat'] = tstat
result['all']['kelly'] = calculate_kelly(positions)
mean = np.mean(list(map(lambda x: x.pnl(), longs)))
stddev = np.std(list(map(lambda x: x.pnl(), longs)))
sharpe = mean / stddev
tstat = sharpe * math.sqrt(len(longs))
result['long']['sharpe_ratio'] = sharpe
z_score = mean / stddev
tstat = z_score * math.sqrt(len(longs))
result['long']['z_score'] = z_score
result['long']['t_stat'] = tstat
result['long']['kelly'] = calculate_kelly(longs)
mean = np.mean(list(map(lambda x: x.pnl(), shorts)))
stddev = np.std(list(map(lambda x: x.pnl(), shorts)))
sharpe = mean / stddev
tstat = sharpe * math.sqrt(len(shorts))
result['short']['sharpe_ratio'] = sharpe
z_score = mean / stddev
tstat = z_score * math.sqrt(len(shorts))
result['short']['z_score'] = z_score
result['short']['t_stat'] = tstat
result['short']['kelly'] = calculate_kelly(shorts)
return result

14
src/naiback/broker/broker.py

@ -15,6 +15,7 @@ class Broker: @@ -15,6 +15,7 @@ class Broker:
self.positions = []
self.retired_positions_ = []
self.commission_percentage = 0
self.commission_fixed = 0
self.timestamp = None
def cash(self):
@ -28,27 +29,30 @@ class Broker: @@ -28,27 +29,30 @@ class Broker:
#if amount > 0:
# if volume * (1 + 0.01 * self.commission_percentage) > self.cash_:
# return None
commission = volume * 0.01 * self.commission_percentage + abs(amount) * self.commission_fixed
pos = Position(ticker)
pos.enter(price, amount, bar=bar_index, timestamp=self.timestamp)
pos.enter(price, amount, bar=bar_index, timestamp=self.timestamp, commission=commission)
self.cash_ -= price * amount
self.cash_ -= volume * 0.01 * self.commission_percentage
self.cash_ -= commission
self.positions.append(pos)
return pos
def close_position(self, pos, price, bar_index):
volume = abs(price * pos.size())
size = pos.size()
pos.exit(price, bar=bar_index, timestamp=self.timestamp)
commission = volume * 0.01 * self.commission_percentage + abs(size) * self.commission_fixed
pos.exit(price, bar=bar_index, timestamp=self.timestamp, commission=commission)
self.retired_positions_.append(pos)
self.positions.remove(pos)
self.cash_ += price * size
self.cash_ -= volume * 0.01 * self.commission_percentage
self.cash_ -= commission
return True
def set_commission(self, percentage):
def set_commission(self, percentage, fixed):
self.commission_percentage = percentage
self.commission_fixed = fixed
def last_position(self):
return self.positions[-1]

31
src/naiback/broker/position.py

@ -30,7 +30,10 @@ class Position: @@ -30,7 +30,10 @@ class Position:
return self.original_size_ < 0
def entry_commission(self):
return self.entry_metadata['commission']
try:
return self.entry_metadata['commission']
except KeyError:
return 0
def entry_bar(self):
return self.entry_metadata['bar']
@ -44,17 +47,35 @@ class Position: @@ -44,17 +47,35 @@ class Position:
def exit_time(self):
return self.exit_metadata['timestamp']
def exit_commission(self):
try:
return self.exit_metadata['commission']
except KeyError:
return 0
def bars_in_trade(self):
return self.exit_bar() - self.entry_bar()
def total_commission(self):
commission = 0
try:
commission += self.entry_commission()
except KeyError:
pass
try:
commission += self.exit_commission()
except KeyError:
pass
return commission
def pnl(self):
return self.total_pnl
return self.total_pnl - self.total_commission()
def profit_percentage(self):
if self.is_long():
return (self.exit_price() / self.entry_price() - 1) * 100.
return (self.exit_price() / self.entry_price() - 1 - (self.total_commission()) / self.entry_price()) * 100.
else:
return -(self.exit_price() / self.entry_price() - 1) * 100.
return (1 - self.exit_price() / self.entry_price() - (self.total_commission()) / self.entry_price()) * 100.
def enter(self, price, amount, **kwargs):
self.entry_price_ = price
@ -66,7 +87,7 @@ class Position: @@ -66,7 +87,7 @@ class Position:
def exit(self, price, **kwargs):
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.total_commission()
self.size_ = 0
for k, v in kwargs.items():

35
src/naiback/data/feeds/yahoofeed.py

@ -0,0 +1,35 @@ @@ -0,0 +1,35 @@
from naiback.data.feed import Feed, Bar
import csv
import datetime
import itertools
class YahooCSVFeed(Feed):
def __init__(self, fp):
self.bars = []
self.ticker_ = None
reader = csv.reader(fp, delimiter=',')
next(reader)
for row in reader:
try:
self.ticker_ = row[0]
open_ = float(row[1])
high = float(row[2])
low = float(row[3])
close = float(row[4])
volume = int(row[6])
date = row[0]
dt = datetime.datetime.strptime(date, "%Y-%m-%d")
self.bars.append(Bar(open_, high, low, close, volume, dt))
except IndexError:
pass
def type(self):
return 'bars'
def items(self):
return self.bars
def ticker(self):
return self.ticker_

4
src/naiback/indicators/__init__.py

@ -5,5 +5,7 @@ from .rsi import RSI @@ -5,5 +5,7 @@ from .rsi import RSI
from .intradaybarnumber import IntradayBarNumber
from .highest import Highest,HighestValue
from .lowest import Lowest,LowestValue
from .atr import ATR
from .atr import ATR, ATR_minus, ATR_plus
from .bollinger import BollingerBands
from .adx import ADX
from .smma import SMMA

33
src/naiback/indicators/adx.py

@ -0,0 +1,33 @@ @@ -0,0 +1,33 @@
import numpy as np
from .atr import ATR
from .ema import EMA
from .smma import SMMA
def ADX(bars, period):
dm_minus = np.zeros(len(bars.close))
dm_plus = np.zeros(len(bars.close))
adx = np.zeros(len(bars.close))
atr = ATR(bars, period)
if len(bars.close) == 0:
return np.array([])
for i in range(1, len(bars.close)):
plus = bars.high[i] - bars.high[i - 1]
minus = -bars.low[i] + bars.low[i - 1]
if plus > 0 and plus > minus:
dm_plus[i] = plus
if minus > 0 and minus > plus:
dm_minus[i] = minus
di_plus = np.asarray(SMMA(dm_plus, period)) * 100 / atr
di_minus = np.asarray(SMMA(dm_minus, period)) * 100 / atr
preprocessed_adx = np.abs(np.nan_to_num(np.divide(di_plus - di_minus, di_plus + di_minus)))
adx = 100 * np.asarray(SMMA(preprocessed_adx, period))
return (adx, di_plus, di_minus)

24
src/naiback/indicators/atr.py

@ -18,3 +18,27 @@ def ATR(bars, period): @@ -18,3 +18,27 @@ def ATR(bars, period):
for i in range(period, len(bars.close)):
atr[i] = (atr[i - 1] * (period - 1) + tr[i]) / period
return atr
def ATR_filtered(bars, period, f):
tr = np.zeros(len(bars.close))
if len(bars.close) == 0:
return np.array([])
tr[0] = bars.high[0] - bars.low[0]
for i in range(1, len(bars.close)):
tr[i] = max(bars.high[i] - bars.low[i], abs(bars.high[i] - bars.close[i - 1]), abs(bars.low[i] - bars.close[i - 1]))
atr = np.zeros(len(bars.close))
if len(bars.close) <= period:
return atr
atr[period - 1] = sum(filter(f, tr[0:period])) / period
for i in range(period, len(bars.close)):
atr[i] = (atr[i - 1] * (period - 1) + tr[i]) / period
return atr
def ATR_plus(bars, period):
return ATR_filtered(bars, period, lambda x : x > 0)
def ATR_minus(bars, period):
return ATR_filtered(bars, period, lambda x : x < 0)

3
src/naiback/indicators/bollinger.py

@ -9,7 +9,8 @@ def BollingerBands(values, period, stddevs): @@ -9,7 +9,8 @@ def BollingerBands(values, period, stddevs):
ma = SMA(values, period)
diffs = ma - np.array(values)
for i in range(period, len(values)):
sigma = np.std(diffs[i-period+1:i+1])
#sigma = np.std(diffs[i-period+1:i+1])
sigma = np.std(values[i-period+1:i+1])
lower[i] = ma[i] - stddevs * sigma
higher[i] = ma[i] + stddevs * sigma

2
src/naiback/indicators/ema.py

@ -6,7 +6,7 @@ def EMA(data, period, alpha=None): @@ -6,7 +6,7 @@ def EMA(data, period, alpha=None):
if alpha is None:
alpha = 2. / (period + 1)
result = []
v = None
v = 0
for d in data:
if d is None:
result.append(None)

13
src/naiback/indicators/smma.py

@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
import numpy as np
def SMMA(values, period):
smma = np.zeros(len(values))
alpha = (period - 1) / period
smma[0] = values[0]
for i in range(1, len(values)):
smma[i] = smma[i - 1] * alpha + values[i] * (1 - alpha)
return smma
Loading…
Cancel
Save