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 Population Variance (Var):
Population 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

[Update] If you want the sample Variance you just need to adjust the Var formula to the following:

Sample Var = (PSA_{today} * n - n * SMA_{today} * SMA_{today}) / (n - 1)

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

Portfolio Performance for October 2010

Back to back months of these kind of numbers make an old trader like me nervous. When’s the trap door going to fall?

No doubt the current market environment is to the system’s liking. One thing I need to explore is the system’s position sizing algo. I position size based on the volatility of the stock over x days. But, lately the volatility on the stocks selected have been so small. Which is seriously underestimating the true risk of the position. So, need to perform some studies on how to handle volatility shrinkage during boom times like these.

On to the charts…
VAMI - October 2010

ROI - October 2010

Drawdown - October 2010
As you can see, we are officially out of the almost 3 year drawdown (knocking on wood as I type this).

What’s ahead for TaylorTree? Spending what free time I have on preparing for another Missouri winter. Don’t believe this Texas boy will ever get used to the cold. Also, working on the continued upgrade of the database and record structures of the simulation engine. Tests so far have proved the new structures are much faster and memory efficient…but have yet to test on the type of data demands the simulation engine handles – 10GB+.

Later Trades,

MT

Portfolio Performance for September 2010

September was a great month for the portfolio. Adding another positive month to the new system’s belt. So far, 3 out of 4 positive months for the new system. Marking August as the only negative month. This reminds me, I need to code some reports to track this type of information. Add it to the many list of things to do. On to the charts:

VAMI - 09/2010

VAMI

As you can see, the portfolio dropped 6% in August followed by a 21% pop in September.

Return on Investment (ROI) - 09/2010

Return on Investment (ROI)

After a great month; it’s easy to pat yourself on the back. If anything the years have taught me; September was just another month. I haven’t done anything to garner a great month or a bad month. Perhaps this quote from Wall Street 2 says it best:

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

Drawdown - 09/2010

Drawdown

Checking out the Drawdown chart above, we’re inching ever closer to getting back to even. Hard to imagine we’ve been living in drawdown for almost 3 years.

That’s it from the trading turret where I’m watching the colorful leaves fall. Looking forward to a weekend of grilling, finishing up some remodel work, and enjoying a few seasonal beers of the Fall.

Later Trades,

MT

Running Sum

We’ve covered Running SMAs and EMAs…let’s dig into Running Sums or often called Running Totals. Formula as follows:
Sum_{today} = Sum_{yesterday} + (price_{today} - price_{today - period})
Where price_{today - period} represents the price that is dropping off the slice you are summing. For example:

Take a list of numbers = 20, 40, 60, 80, 100, 120.
The formula for the 3-bar running sum would be:
bar 1: 20
bar 2: 20 + 40 = 60
bar 3: 20 + 40 + 60 = 120

bar 4: 40 + 60 + 80 = 180
Or we can apply our formula from above as Sum_{today} = 120 + (80 - 20)

bar 5: 60 + 80 + 100 = 240
Or use formula of Sum_{today} = 180 + (100 - 40)

bar 6: 80 + 100 + 120 = 300
Or use formula of Sum_{today} = 240 + (120 - 60)

Coding in Python we get:

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

Portfolio Performance for July 2010

One thing I’ve noticed in trading systems over the years is the observer effect. Typically, when a thoroughly backtested system fails…the trader will dismiss the system as being too optimized. You never hear about the observer effect with real-time trading of the system. That is probably the most difficult aspect of developing systems. Just the mere fact of participating in the price pattern you’ve discovered changes the price pattern. Despite how small a fish you may be in the market.

All we can hope for as system traders is finding an edge that is large enough to accommodate the increased order flow. So, when we jump in and reduce the edge…there is still enough leftover for us to be profitable. I guess, that is why I’ve always traded very long-term systems. And probably why I still lack confidence in this new short-term mean-reversion system.

Moving on…

July was an excellent month for the market. The portfolio was trounced. But, still finished the month with another positive number. This marks the second month trading the new system.

TaylorTree VAMI as of 07/2010

TaylorTree ROI as of 07/2010

TaylorTree Drawdown as of 07/2010

Adding a new chart to the reporting: Investment Levels. This reflects the amount of capital that TaylorTree is invested at the end of the month. As you can see, when the portfolio is less than 100% invested in the market and the market has a month like this one…it is extremely difficult to beat it. Cash drag kills you when the market turns around.
TaylorTree Investment Levels as of 07/2010

The picture above of the alligator is from our stay at The Retreat at Artesian Lakes located just outside Cleveland, TX. They had several cabins overlooking the lakes. Step out on your front porch and this 6ft alligator would come swimming up – day or night.

Later Trades,

MT

Go to top