Goals of trading and investing

Tadas Talaikis
BlueBlood
Published in
3 min readAug 16, 2018
Photo by Voicu Oara from Pexels

As we can see from the following distribution of SPY (S&P500 index ETF) daily returns, they are basically random, having pretty equal left (negative returns) and right (positive returns) sides with little average upside.

from numpy import sortdf['ret'] = df['SPY_Close'].pct_change()
df = df.dropna()
_sorted = sort(df['ret'].values)
plt.hist(_sorted, bins=300)
plt.axvline(df['ret'].mean())
plt.show()

As such, goals of trading and investing is to:

  1. Minimize the left tail (e.g., minimize losses).
  2. Maximize the right tail (profit).
  3. Maximize win rate.

First two try to achieve good utility (satisfaction) for investor’s defined risk aversion profile. Third is important, because risk of ruin depends primarily on win rate, i.e., you should have predictive (alpha) model to avoid consecutive losers, and as such, minimize risk of ruin.

Let’s try most often used example of moving average strategy. We’ll buy when price is above 200 days moving average and do nothing when prices are below:

from numpy import where
from matplotlib import pyplot as plt
from app.data import get_pickle
def main():
df = get_pickle('tiingo', 'SPY')
df['SPY returns'] = df['SPY_Close'].pct_change()
df['sma'] = df['SPY_Close'].rolling(window=200, min_periods=200).mean()
df['signal'] = where(df['SPY_Close'] > df['sma'], 1, 0)
df['Strategy returns'] = df['signal'].shift() * df['SPY returns']
df[['Strategy returns', 'SPY returns']].cumsum().plot()
plt.show()

Resulting curve as compared to same curve without this strategy:

Let’s compare our strategy distribution with the benchmark, out from which we tried to achieve some improvements:

sorted_strategy = sort(strategy.values)
sorted_benchmark = sort(df['SPY returns'].dropna().values)
plt.hist(sorted_benchmark, bins=300, color='g')
plt.hist(sorted_strategy, bins=300, color='r')
plt.axvline(df['SPY returns'].mean(), color='g')
plt.axvline(strategy.mean(), color='r')
plt.show()

What we see, no difference in distributions, demonstrating my previous point that anything in technical “analysis” is just trading on random noise, slightly worse average trade (not even including trading costs). Maybe risk is improved?

from numpy import sqrtbenchmark_sharpe = df['SPY returns'].mean() / df['SPY returns'].std() * sqrt(252)
strategy_sharpe = strategy.mean() / strategy.std() * sqrt(252)
print('Strategy Sharpe Ratio %.2f' % strategy_sharpe)
print('Benchmark Sharpe Ratio %.2f' % benchmark_sharpe)
Strategy Sharpe Ratio 0.66
Benchmark Sharpe Ratio 0.49

Sharpe is a bit better, although common sense of such strategy is pretty small improvement over benchmark:

from numpy import percentile
def common_sense(returns):
profits = sum(where(returns > 0, returns, 0))
losses = sum(where(returns < 0, returns, 0))
return (percentile(returns, 95) * profits) / (percentile(returns, 5) * losses)

Strategy Common Sense Ratio 1.09
Benchmark Common Sense Ratio 1.03

What about win rate?

w1 = sum(where(strategy > 0, 1, 0)) / len(strategy)
w2 = sum(where(df['SPY returns'] > 0, 1, 0)) / len(df['SPY returns'])
print('Strategy Win rate %.2f%%' % (w1 * 100))
print('Benchmark Win rate %.2f%%' % (w2 * 100))
Strategy Win rate 54.11%
Benchmark Win rate 53.12%

Well, just one additional win trade per 100, and as we know from above distributions comparison, average such winning trade is worse than benchmark’s.

So, probably such strategy doesn’t hold defined goals for trading and investing well.

--

--