Portfolio Performance for Feb 2011

# of Entries...........8
# of Exits.............7
WinRatio..............80.00%

Portfolio's ROI........5.82%
Market's ROI...........3.20%

February was a good month for the market and portfolio. The portfolio edging out the market’s return for another month.

Going to go on a bit of a rant here. Something that has bothered me a bit in the trading world for years — trading psychology. Trading psychology is a market unto itself. Books, blogs, websites, all kinds of info to help you become a better trader. Most of it? The wrong focus.

Why? The crux of the trading psychology stance is — don’t trade a system (even if its profitable) if it doesn’t match your personality. It’s all about finding the right match. Like those eHarmony commercials.

The trading world wants to embrace a yoga or martial arts viewpoint on trading success. Reminds me how people judged martial arts disciplines prior to UFC coming to light. In fact, I wrote about trading and fighting in a post almost 6 years back here.

Before there was a venue for everyone to see which fighting styles worked…students were inundated with rhetoric, philosophy, etc. You had all these theories about what worked in a real fight. But, nobody was fighting. Just talking and practicing strict rigid disciplines. Then the UFC came along and all these martials arts disciplines came together and actually fought. The winner shocking everyone. All these wonderful well thought-out disciplines just failed. All the finding one’s chi and structured katas just failed. Turns out…you’ve got to fight. It isn’t about finding yourself. Isn’t about finding your chi. It’s about fighting your opponent. It’s about taking advantage of your strengths and their weaknesses. See this video for the story behind UFC and the 1st winner of UFC. Please note…video shows real fighting. And be sure to see Ken Shamrock’s interview around 6:18 mark. Along with Joe Rogan’s comments around 9:24.

That’s why I wince every time I hear or read about finding a trading system that fits your personality. Or there’s only one way of trading – as we often hear with trend following. Damn, that’s a religion all unto itself.

Gracie took advantage of his amazing ground game and everyone’s lack of to win. But, you cannot stop there. You have to adapt…because your competitor’s adapt. The market adapts. The UFC adapts. There is no holy grail. No one way to do things. No black and white. It’s all gray. It’s all changing…all the time. Cause the participant’s are learning all the time.

It’s not about finding a system your comfortable with. It’s about getting comfortable with a winning system.

Despite the religion behind trend-following…I think it’s one of the best places to learn how to fight. It teaches you how to get comfortable on your back when the market is clearly kicking your tail. It limits the number of decisions you have to make at a time when your trading instincts and intellect are screaming to run away. Teaching you how to get comfortable with being uncomfortable in trading.

So, observe the markets, find profitable rules, and trade them. Despite how uncomfortable you find yourself trading them. Cause it’s not about you…as Charlie Sheen so eloquently states…it is about winning.

Later Trades,

MT

Portfolio Performance for January 2011

The portfolio finished the month up 2.82%. Not a particularly stellar month for the portfolio; but I’ll take a win over the market anytime.

# of Entries.......8
# of Exits.........7

As you can see with the above entries & exits; still not much activity for the portfolio in January. I’m hoping this next month brings more action to the table.

On the development side of the house; I hit a snag with the simulation engine’s backend database architecture. So, I’ve spent a few weeks performance testing the database components. I believe I’ve got all the performance issues squared away and plan to get back on track with the conversion over the next few weeks.

Later Trades,

MT

Portfolio Performance for December 2010

Market did great in December (+6.53%); while the portfolio was stuck in neutral (-0.36%).


The majority of positions just didn’t budge. As a result, most positions were held to term limit. Which dropped the monthly number of trades down a bit when compared to average.

# of Trades for Dec 2010:
# of Long Entries……..7
# of Long Exits………. 7

Goal for January is to start migrating the backtesting engine from the old database design to the hopefully new & improved version.

As a side note, I’ve added a new movie to my all-time favorites list: The Social Network. A must-see if you’ve ever hacked a few lines here or there.

Later Trades,

MT

Collecting Max Items in Python

Lately, I’ve needed a way to collect a running list of the top X values and their associated items in Python. This is useful if you’d like to know such things as:

  • Top 100 price gainers in your price series database;
  • Top 10 most volatile stocks in your price series database;
  • Top 5 longest running batch jobs in your operations arena;
  • Any many more…

Here’s the MaxItems code to do the job:

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. I’ll cover the MinItems class in another post. But, to give you a hint of what does work in collecting the minimum values over a list is one of the alternatives I explored in building the MaxItems class…

Alternative yet Inefficient version of MaxItems:

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.

Test Code:

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:

  • heapq method: Ten iterations finished in 1.90 seconds.
  • bisect method: Ten iterations finished in 3.80 seconds.

If you know of a faster way to collect the top x of a group of items…please share.

MT

Portfolio Performance for November 2010

Portfolio ended the month of November up 1.65% versus the market’s -.23%. Sure doesn’t reflect the volatility that November gave us.

VAMI - November 2010

ROI - November 2010

Drawdown - November 2010

The difficulty in managing a portfolio, as we all know, is handling “emotions”. Most people when they think of emotions think of impulsiveness, recklessness, and not thinking things through. I’m not describing that at all. Dealing with emotions is dealing with my logic and experience. You’ve got a system handing you signals that have been thoroughly tested in all kinds of markets. But, your intellect wants to use your experience and logic to protect the portfolio from market damage.

You are bombarded with all the facts surrounding the markets and your brain wants to assemble the pieces into a perfect future of the investment landscape. You’ve got years of market experience, sound reasoning, and other “smart” market pundits and prognosticators on your side demanding you to interject your system’s signals. How can you possibly take this next trade when the market’s volatility is too smooth? Not enough risk is being reflected in the markets. The market has gone up too far and too fast for too long. The trap door is in plain sight and will open and your returns will fall…right?

This is why I trade systems. To protect my portfolio from the “emotions” of my highly analytical mind. And this November was a wonderful reinforcement of that lesson. I can’t stress enough how important it is to review your backtests, especially the drawdowns and corresponding recoveries. Ask yourself, can you still enter trades given the investment landscape in that time period? Really think about this question…because that question will pop up often in your system trading future.

Later Trades,

MT

Running Variance

Variance – kinda the bread and butter for analysis work on a time series. Doesn’t get much respect though. But, take the square root of the variance and you get the almighty standard deviation. Today, though, let’s give variance its due…

For an intro into variance…check out these posts:

Problem with variance is calculating it in the traditional sense. Its costly to compute across a time series. It can be quite a drag on your simulation engine’s performance. The way to reduce the cost is to calculate the running variance. And that’s when you get into quite a briar patch – loss of precision and overflow issues. See John D. Cook’s post covering the variance briar patch:

And a few more posts by John covering different variance formulas and their outcomes:

John does great work and I learn a lot from his posts. But, I was still having problems finding a variance formula that fit my needs:

  • Reduced the precision loss issue as much as possible;
  • Allowed an easy way to window the running variance;
  • Allowed an easy way to memoize the call.

Thankfully, I found a post by Subluminal Messages covering his very cool Running Standard Deviations formula. The code doesn’t work as is – needs correcting on a few items – but you can get the gist of the formula just fine. The formula uses the power sum of the squared differences of the values versus Welford’s approach of using the sum of the squared differences of the mean. Which makes it a bit easier to memoize. Not sure if its as good in solving the precision loss and overflow issues as Welford’s does….but so far I haven’t found any issues with it.

So, let’s start with the formula for the Power Sum Average (PSA):
PSA = PSA_{yesterday} + ( ( (x_{today} * x_{today}) - x_{yesterday} ) ) / n)
Where:

  • x = value in your time series
  • n = number of values you’ve analyzed so far

You also need the Simple Moving Average, which you can find in one of my previous posts here.

Once you have the PSA and SMA; you can tackle the Running Variance (Var):
Var = (PSA_{today} * n - n * SMA_{today} * SMA_{today}) / n

Now, one problem with all these formulas – they don’t cover how to window the running variance. Windowing the variance gives you the ability to view the 20 period running variance at bar 150. All the formulas I’ve mentioned above only give you the running cumulative variance. Deriving the running windowed variance is just a matter of using the same SMA I’ve posted about before and adjusting the Power Sum Average to the following:
PSA = PSA_{yesterday} + (((x_{today} * x_{today}) - (x_{yesterday} * x_{yesterday}) / n)
Where:

  • x = value in your time series
  • n = the period

Okay, on to the code.

Code for the Power Sum Average:

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 result

Code 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) / windowsize

Example 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.2222

Of 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.

Later Trades,

MT