# of Entries...........8 # of Exits.............9 WinRatio..............77.78% Portfolio's ROI.......+3.44% Market's ROI..........-1.35%
Later Trades,
MT
The critical ingredient is a maverick mind. Focus on trading vehicles, strategies and time horizons that suit your personality. In a nutshell, it all comes down to: Do your own thing (independence); and do the right thing (discipline). -- Gil Blake
# of Entries...........7 # of Exits.............6 WinRatio..............66.66% Portfolio's ROI.......+0.89% Market's ROI..........+2.85%
# of Entries...........8 # of Exits............10 WinRatio..............70.00% Portfolio's ROI.......+3.38% Market's ROI..........-0.10%
# of Entries...........8 # of Exits.............7 WinRatio..............80.00% Portfolio's ROI........5.82% Market's ROI...........3.20%
It's not about finding a system your comfortable with. It's about getting comfortable with a winning system.
# of Entries.......8 # of Exits.........7
import heapq class MaxItems(object): """ Caches the max X items of whatever you're analyzing and returns a list containing only those max X values and associated items. """ def __init__(self, size): self.size = size self._recs = [] def push(self, value, items): if len(self._recs) < self.size: heapq.heappush(self._recs, (value, items)) else: minitem = heapq.heappushpop(self._recs, (value, items)) def items(self): return heapq.nlargest(self.size, self._recs)Example call and results:
pricegains = [] pricegains.append({'symbol':'GOOG', 'gain':234.0}) pricegains.append({'symbol':'YHOO', 'gain':124.0}) pricegains.append({'symbol':'IBM', 'gain':1242.0}) pricegains.append({'symbol':'GE', 'gain':1800.0}) pricegains.append({'symbol':'ENE', 'gain':0.0}) pricegains.append({'symbol':'KREM', 'gain':12.0}) maxitems = MaxItems(3) for row in pricegains: maxitems.push(row['gain'], row) print maxitems.items() ---------------------------------------------------------- Results of call: (1800.0, {'symbol': 'GE', 'gain': 1800.0}) (1242.0, {'symbol': 'IBM', 'gain': 1242.0}) (234.0, {'symbol': 'GOOG', 'gain': 234.0})The heapq module works nicely in accomplishing the task. What's ironic is Python's heapq module implements the min-heap algorithm which works out nicely and efficiently in determining the maximum values over a list. But, does not work out so efficiently for determining the minimum values over a list.
import bisect class MaxItems2(object): """ Caches the max X items of whatever you're analyzing and returns a list containing only those max X values and associated items. """ def __init__(self, size): self.size = size self._recs = [] def push(self, value, items): if len(self._recs) < self.size: bisect.insort(self._recs, (value, items)) elif bisect.bisect(self._recs, (value, items)) > self.size: bisect.insort(self._recs, (value, items)) minitem = self._recs.pop(0) def items(self): return sorted(self._recs, reverse=True)MaxItems2 takes advantage of the bisect module and while it works great; performance is at a minimum 2x worse on average than using the heapq method.
import random pricegains = [] maxitems = MaxItems(100) for x in xrange(500000): gain = random.uniform(1.0,500.0) maxitems.push(gain, ('This', 'is', 'Record')) rows = maxitems.items()Calling the above code with the wonderful timeit module produced the following results:
def powersumavg(bar, series, period, pval=None): """ Returns the power sum average based on the blog post from Subliminal Messages. Use the power sum average to help derive the running variance. sources: http://subluminal.wordpress.com/2008/07/31/running-standard-deviations/ Keyword arguments: bar -- current index or location of the value in the series series -- list or tuple of data to average period -- number of values to include in average pval -- previous powersumavg (n - 1) of the series. """ if period < 1: raise ValueError("period must be 1 or greater") if bar < 0: bar = 0 if pval == None: if bar > 0: raise ValueError("pval of None invalid when bar > 0") pval = 0.0 newamt = float(series[bar]) if bar < period: result = pval + (newamt * newamt - pval) / (bar + 1.0) else: oldamt = float(series[bar - period]) result = pval + (((newamt * newamt) - (oldamt * oldamt)) / period) return resultCode for the Running Windowed Variance:
def running_var(bar, series, period, asma, apowsumavg): """ Returns the running variance based on a given time period. sources: http://subluminal.wordpress.com/2008/07/31/running-standard-deviations/ Keyword arguments: bar -- current index or location of the value in the series series -- list or tuple of data to average asma -- current average of the given period apowsumavg -- current powersumavg of the given period """ if period < 1: raise ValueError("period must be 1 or greater") if bar <= 0: return 0.0 if asma == None: raise ValueError("asma of None invalid when bar > 0") if apowsumavg == None: raise ValueError("powsumavg of None invalid when bar > 0") windowsize = bar + 1.0 if windowsize >= period: windowsize = period return (apowsumavg * windowsize - windowsize * asma * asma) / windowsizeExample call and results:
list_of_values = [3, 5, 8, 10, 4, 8, 12, 15, 11, 9] prev_powersumavg = None prev_sma = None prev_sma = None period = 3 for bar, price in enumerate(list_of_values): new_sma = running_sma(bar, list_of_values, period, prev_sma) new_powersumavg = powersumavg(bar, list_of_values, period, prev_powersumavg) new_var = running_var(bar, list_of_values, period, new_sma, new_powersumavg) msg = "SMA=%.4f, PSA=%.4f, Var=%.4f" % (new_sma, new_powersumavg, new_var) print "bar %i: %s" % (bar, msg) prev_sma = new_sma prev_powersumavg = new_powersumavg ---------------------------------------------------------- Results of call: bar 0: SMA=3.0000, PSA=9.0000, Var=0.0000 bar 1: SMA=4.0000, PSA=17.0000, Var=1.0000 bar 2: SMA=5.3333, PSA=32.6667, Var=4.2222 bar 3: SMA=7.6667, PSA=63.0000, Var=4.2222 bar 4: SMA=7.3333, PSA=60.0000, Var=6.2222 bar 5: SMA=7.3333, PSA=60.0000, Var=6.2222 bar 6: SMA=8.0000, PSA=74.6667, Var=10.6667 bar 7: SMA=11.6667, PSA=144.3333, Var=8.2222 bar 8: SMA=12.6667, PSA=163.3333, Var=2.8889 bar 9: SMA=11.6667, PSA=142.3333, Var=6.2222Of course, as I said in the beginning of this post, just take the square root of this Running Windowed Variance to obtain the Standard Deviation.
Jacob: "How's your day going?"
Lewis: "I told you...good day I'm okay, bad day...I'm okay. Stop bugging me on my feelings, their irrelevant."
bar 1: 20 bar 2: 20 + 40 = 60 bar 3: 20 + 40 + 60 = 120 bar 4: 40 + 60 + 80 = 180Or we can apply our formula from above as \( Sum_{today} = 120 + (80 - 20) \)
bar 5: 60 + 80 + 100 = 240Or use formula of \( Sum_{today} = 180 + (100 - 40) \)
bar 6: 80 + 100 + 120 = 300Or use formula of \( Sum_{today} = 240 + (120 - 60) \)
def running_sum(bar, series, period, pval=None): """ Returns the running sum of values in a list of tuple - avoids summing entire series on each call. Keyword arguments: bar -- current index or location of the value in the series series -- list or tuple of data to sum period -- number of values to include in sum pval -- previous sum (n - 1) of the series. """ if period < 1: raise ValueError("period must be 1 or greater") if bar <= 0: return series[0] if bar < period: return pval + series[bar] return pval + (series[bar] - series[bar - period])Example call and results:
list_of_values = [20, 40, 60, 80, 100, 120] prevsum = list_of_values[0] #first sum is the first value in the series. for bar, price in enumerate(list_of_values): newsum = running_sum(bar, list_of_values, 3, pval=prevsum) print "bar %i: %i" % (bar, newsum) prevsum = newsum ---------------------------------------------------------- bar 0: 20 bar 1: 60 bar 2: 120 bar 3: 180 bar 4: 240 bar 5: 300
def ema(bar, series, period, prevma, smoothing=None): '''Returns the Exponential Moving Average of a series. Keyword arguments: bar -- currrent index or location of the series series -- series of values to be averaged period -- number of values in the series to average prevma -- previous exponential moving average smoothing -- smoothing factor to use in the series. valid values: between 0 & 1. default: None - which then uses formula = 2.0 / (period + 1.0) closer to 1 to gives greater weight to recent values - less smooth closer to 0 gives greater weight to older values -- more smooth ''' if period < 1: raise ValueError("period must be 1 or greater") if smoothing: if (smoothing < 0) or (smoothing > 1.0): raise ValueError("smoothing must be between 0 and 1") else: smoothing = 2.0 / (period + 1.0) if bar <= 0: return series[0] elif bar < period: return cumulative_sma(bar, series, prevma) return prevma + smoothing * (series[bar] - prevma) def cumulative_sma(bar, series, prevma): """ Returns the cumulative or unweighted simple moving average. Avoids averaging the entire series on each call. Keyword arguments: bar -- current index or location of the value in the series series -- list or tuple of data to average prevma -- previous average (n - 1) of the series. """ if bar <= 0: return series[0] else: return prevma + ((series[bar] - prevma) / (bar + 1.0))
prices = [32.47, 32.70, 32.77, 33.11, 33.25, 33.23, 33.23, 33.0, 33.04, 33.21] period = 5 #number of bars to average prevsma = prevema = prices[0] #1st day nothing to average for bar, close in enumerate(prices): currentema = ema(bar, prices, period, prevema, smoothing=None) #running_sma defined in simple moving average blog post currentsma = running_sma(bar, prices, period, prevsma) print "Day %02d Value=%.2f %i-bar SMA=%f and EMA=%f" % (bar + 1, close, period, currentsma, currentema) prevema = currentema prevsma = currentsma ---------------------------------------------------------- Results of call: Day 01 Value=32.47 5-day SMA=32.470000 and EMA=32.470000 Day 02 Value=32.70 5-day SMA=32.585000 and EMA=32.585000 Day 03 Value=32.77 5-day SMA=32.646667 and EMA=32.646667 Day 04 Value=33.11 5-day SMA=32.762500 and EMA=32.762500 Day 05 Value=33.25 5-day SMA=32.860000 and EMA=32.860000 Day 06 Value=33.23 5-day SMA=33.012000 and EMA=32.983333 Day 07 Value=33.23 5-day SMA=33.118000 and EMA=33.065556 Day 08 Value=33.00 5-day SMA=33.164000 and EMA=33.043704 Day 09 Value=33.04 5-day SMA=33.150000 and EMA=33.042469 Day 10 Value=33.21 5-day SMA=33.142000 and EMA=33.098313
"Time flies like an arrow; fruit flies like a banana" -- Groucho Marx
def cumulative_sma(bar, series, prevma): """ Returns the cumulative or unweighted simple moving average. Avoids sum of series per call. Keyword arguments: bar -- current index or location of the value in the series series -- list or tuple of data to average prevma -- previous average (n - 1) of the series. """ if bar <= 0: return series[0] return prevma + ((series[bar] - prevma) / (bar + 1.0))
def running_sma(bar, series, period, prevma): """ Returns the running simple moving average - avoids sum of series per call. Keyword arguments: bar -- current index or location of the value in the series series -- list or tuple of data to average period -- number of values to include in average prevma -- previous simple moving average (n - 1) of the series """ if period < 1: raise ValueError("period must be 1 or greater") if bar <= 0: return series[0] elif bar < period: return cumulative_sma(bar, series, prevma) return prevma + ((series[bar] - series[bar - period]) / float(period))And the example call and results:
prices = [10, 15, 25, 18, 13, 16] prevsma = prices[0] #1st day nothing to average so return itself. for bar, close in enumerate(prices): currentsma = running_sma(bar, prices, 3, prevsma) print "Today's 3-day SMA = %.4f" % currentsma prevsma = currentsma ------- Results ---------------- Today's 3-day SMA = 10.0000 Today's 3-day SMA = 12.5000 Today's 3-day SMA = 16.6667 Today's 3-day SMA = 19.3333 Today's 3-day SMA = 18.6667 Today's 3-day SMA = 15.6667
Key Figures | Russell 3000 | IWV |
---|---|---|
Total Active Components | 2961 | 1 |
Total New Listings this period | 0 | 0 |
Total Inactive this period | 1 | 0 |
# All-time Closing Highs | 28 (0.19%) | 0 (0.00%) |
# All-time Closing Lows | 87 (0.59%) | 0 (0.00%) |
# Higher Closes | 6755 (45.63%) | 2 (40.00%) |
# Lower Closes | 7775 (52.52%) | 3 (60.00%) |
Total Gains/Losses | $1059.55 (0.28%) | $0.45 (0.14%) |
Average True Range | (4.59%) | (2.51%) |
Key Figures | Russell 3000 | IWV |
---|---|---|
Total Active Components | 2961 | 1 |
Total New Listings this period | 0 | 0 |
Total Inactive this period | 0 | 0 |
# All-time Closing Highs | 10 (0.34%) | 0 (0.00%) |
# All-time Closing Lows | 6 (0.20%) | 0 (0.00%) |
# Higher Closes | 508 (17.16%) | 0 (0.00%) |
# Lower Closes | 2402 (81.12%) | 1 (100.00%) |
Total Gains/Losses | $-1023.98 (-1.33%) | $-0.72 (-1.10%) |
Average True Range | (3.77%) | (1.66%) |