def test_div(self): self.assertEqual(mu.div(0,0), 0) self.assertEqual(mu.div(0,1), 0) self.assertEqual(mu.div(1,0), float('inf')) self.assertEqual(mu.div(2,1), 2.) self.assertEqual(mu.div(2,1.25), 1.6) self.assertEqual(mu.div(2,0.5), 4.) self.assertEqual(mu.div(0.5,0.25), 2.) self.assertEqual(mu.div(0.2, 0.1), 2.)
def get_list(self, stock_list, date, **kwargs): ranked_stocklist = [] for stock in stock_list: quality = div(stock.price.channel.angle(self.lb)[date], stock.price.channel.width(self.lb)[date]) vsl = stock.price.channel.stoploss(self.lb, date) vsl_p = 100 * (1 - vsl / stock.price.close[date]) valid = (quality > self.thq) and (vsl_p < self.ths) ranked_stocklist.append((stock, quality, valid)) ranked_stocklist.sort(key=operator.itemgetter(1), reverse=True) return ranked_stocklist
def quality(self, lookback): ''' Return a DatedList with the channel quality for <lookback> days. ''' if lookback not in self._data: self._load_data(lookback) if 'quality' not in self._data[lookback]: data = [div(a, w) for a, w in zip(self.angle(lookback).as_list(), self.width(lookback).as_list())] self._data[lookback]['quality'] = DatedList(data, self.angle(lookback).dates) return self._data[lookback]['quality']
def drawdown(dd_list): ''' Returns the highest drawdown in dd_list. ''' max_dd = 1 high = 0 for value in dd_list: if value > high: high = value else: dd = div(value, high) if dd is not None and dd < max_dd: max_dd = dd return 100. * (1 - max_dd)
def get_list(self, stock_list, date, **kwargs): ranked_stocklist = [] for stock in stock_list: # value = div(stock.price.channel.angle(self.lb)[date] * # stock.price.channel.bottom(self.lb)[date], # stock.price.channel.width(self.lb)[date] * # stock.price.close[date]) value = div(stock.price.channel.angle(self.lb)[date], stock.price.channel.width(self.lb)[date] ) * (1 - stock.price.channel.rc(self.lb)[date]) valid = getattr(operator, self.op)(value, self.thq) ranked_stocklist.append((stock, value, valid)) ranked_stocklist.sort(key=operator.itemgetter(1), reverse=(self.op == 'gt')) return ranked_stocklist
def calc_results(self): ''' Returns a dict with: * max_dd: The maximum drawdown over a 1 year period. * min_dd_ratio: The lowest ratio of gain/max_dd in any one year period. * min_month: The lowest gain in any calender month (or highest loss) * max_month: The highest gain in any calender month (or lowest loss) * neg_month: the average number of negative months per year * sum_neg_months: the annualised sum of the losses during those months * ann_gain: annualised profit in % * min_year: The lowest gain in any 1 year period * max_year: The highest gain in any 1 year period ''' year = 252 # avg no of trading days in a year data = {'max_dd':0, 'min_dd_ratio': 999.99} year_gains = self.total.roc(year)[year-1:] if len(year_gains): data['min_year'] = min(year_gains) data['max_year'] = max(year_gains) else: data['min_year'] = 0 data['max_year'] = 0 year_drawdowns = self.total.drawdown(year) for year_dd, year_gain in zip(year_drawdowns, year_gains)[year-1:]: dd_ratio = div(year_gain, year_dd) # in %/% data['max_dd'] = max(data['max_dd'], year_dd) if dd_ratio is not None: data['min_dd_ratio'] = min(data['min_dd_ratio'], dd_ratio) total_gain = max(0, self.total[-1] / self.total[0]) dt = self.total.dates[-1] - self.total.dates[0] data['ann_profit'] = 100 * (total_gain ** (365./dt.days) - 1) months = self.get('month') data['min_month'] = min([x['period_gain'] for x in months]) data['max_month'] = max([x['period_gain'] for x in months]) neg_months = [x['period_gain'] for x in months if x['period_gain'] < 0] data['n_neg_month'] = 12. * len(neg_months) / len(months) data['sum_neg_mths'] = 12. * sum(neg_months) / len(months) # sanitise results: data['max_dd'] = min (data['max_dd'], 99) for key in ('ann_profit', 'sum_neg_mths', 'min_year', 'max_year', 'min_month', 'max_month', 'min_dd_ratio'): data[key] = min(max(data[key], -999), 999) return data
def tmp_translate(): ''' Use (rewrite) this to translate columns ''' import datetime from system.models import System from pyutillib.math_utils import div from django.db import transaction systems = System.objects.all() with transaction.commit_on_success(): for sys in systems: tp = float(sys.expectancy) * sys.n_total dt = datetime.date(2012, 6, 30) - datetime.date(2008, 1, 1) sys.profit_pa = tp * 365./dt.days sys.true_avg_loss = float(sys.avg_loss) * (1 - float(sys.reliability)/100.) sys.profit_ratio = div(float(sys.profit_pa), float(sys.true_avg_loss)) if sys.profit_ratio > 99.99: sys.profit_ratio = 99.99 sys.save()
def _get_rank(self, angle, width): value = div(angle, width) valid = getattr(operator, self.op)(value, self.thq) return value, valid
def calc_performance(self, startdate, enddate, max_pos): ''' Return a dict with standard performance parameters from [trades]. NOTE: if the open positions in the positions need to be part of the performance data, call the <Trades.extend> method with the argument <Positions.close> before this one. ''' self.data = {'max_pos': max_pos, 'max_win': 0, 'max_loss': 0, 'max_n_loss': 0, 'max_n_win': 0} n_win = n_loss = total_win = total_loss = total_days = 0 consec_win = consec_loss = 0 profits = [] cum_gains = [] prevgain = 1 for trade in self.trades: # if trade.is_entrysignal: continue total_days += trade.n_days() gain = trade.gain() # gain is a fraction: 1.0 means 0 profit new_gain = prevgain * gain cum_gains.append(new_gain) prevgain = new_gain profit = 100 * (gain - 1.) profits.append(profit) if profit > 0: n_win += 1 total_win += profit self.data['max_win'] = max(self.data['max_win'], profit) consec_loss = 0 consec_win += 1 else: n_loss += 1 total_loss -= profit self.data['max_loss'] = max(self.data['max_loss'], -profit) consec_loss += 1 consec_win = 0 self.data['max_n_loss'] = max(consec_loss, self.data['max_n_loss']) self.data['max_n_win'] = max(consec_win, self.data['max_n_win']) self.data['avg_win'] = div(total_win, n_win) self.data['avg_loss'] = div(total_loss, n_loss) n_total = n_win + n_loss self.data['reliability'] = 100. * div(n_win, n_total) self.data['profit_factor'] = div(total_win, total_loss) total_profit = total_win - total_loss self.data['expectancy'] = div(total_profit, n_total) variance = ((x - self.data['expectancy'])**2 for x in profits) self.data['std_dev'] = div(sum(variance), n_total) ** 0.5 self.data['sqn'] = div(self.data['expectancy'], self.data['std_dev']) if self.data['sqn'] is not None: self.data['sqn'] *= (n_total ** 0.5 if n_total < 100 else 10.) self.data['days_p_trade'] = div(total_days, n_total) self.data['exp_p_day'] = div(self.data['expectancy'], self.data['days_p_trade']) n_years = (enddate - startdate).days / 365. self.data['profit_pa'] = div(total_profit, n_years * max_pos) self.data['true_avg_loss'] = div(total_loss, n_total) self.data['trades_pa'] = int(n_total / n_years + 0.499999) self.data['profit_ratio'] = div(self.data['profit_pa'], self.data['true_avg_loss'] * self.data['trades_pa']) for key in self.data: if isinstance(self.data[key], float): self.data[key] = min (self.data[key], 999.99) self.data[key] = max (self.data[key], -999.99)