# Backtesting Stochastic Oscillator, SMA, and WMA Trading Strategy with Bitcoin

I have seen a video on youtube by Trader Pro that claimed using Stochastic Oscillator, SMA and WMA together would be a very profitable strategy. The video that claimed using 5 minute and hourly data the strategy had a 47% win rate and the returns were 41%. The video is in the references. I wondered how it would fare with bitcoin. I mimicked that strategy and backtested it with Bitcoin historical data. In this article I will show my backtesting results and give the python code so you can do your own analyses if you wanted to. I used Backtesting.py module.

## The Strategy

SMA(5) is simple moving average of 5 periods (it is 5 x 5 minutes or 5 x 1 hour), WMA(144) is the weighted moving average for 144 periods (it is 144 x 5 minutes or 144 x 1 hour). STOCHASTIC(14) is the Stochastic Oscillator for 14 periods, it returns Slow K and Slow D values.

• One hour SMA(5) > WMA(144) and
• Five minute SMA(5) > WMA(144) and
• STOCHASTIC(14) < 20 and
• Slow K is greater than Slow D.

Sell when: this part was not clear. It was rather subjective, you had to pick the prior low close and twice that amount would be your profit target. So I picked the following exit strategy:

• Use a fixed profit and stop loss. (1% stop loss twice that, %2, profit target, we can also optimize these numbers.)

## Results and Interpretation

I took the last two months bitcoin 5 minute Open, High, Low, Close (OHCL) data from March 1st to May 5th 2021. For fixed stop loss and profit I began with 1% stop loss and 2% profit. I used both long and short positions. Here are the results:

``````Start                     2021-03-01 00:00:00
End                       2021-05-05 23:55:00
Duration                     65 days 23:55:00
Exposure Time [%]                    33.21934
Equity Final [\$]                 847023.91686
Equity Peak [\$]                  1027969.5116
Return [%]                         -15.297608
Buy & Hold Return [%]               27.703443
Return (Ann.) [%]                   -60.07534
Volatility (Ann.) [%]               14.565408
Sharpe Ratio                              0.0
Sortino Ratio                             0.0
Calmar Ratio                              0.0
Max. Drawdown [%]                  -21.524675
Avg. Drawdown [%]                   -2.614039
Max. Drawdown Duration       57 days 07:00:00
Avg. Drawdown Duration        5 days 09:28:00
Win Rate [%]                        32.352941
Max. Trade Duration           1 days 08:05:00
Avg. Trade Duration           0 days 05:05:00
Profit Factor                        0.808772
Expectancy [%]                      -0.156044
SQN                                 -1.150134``````

The win rate is 32% and we made negative returns. This is probably we set our profit target too short. But it is risk management, we could have set them even in fractional percentages. But thinking about commissions, I think at least 1% is required for profit. Then I optimized profit and stoploss values. Here are the best 10 values.

``````profit_short  profit  stop_loss  stop_loss_short
91            106     95         101                1.543821e+06
96         101                1.486828e+06
95         102                1.480832e+06
103                1.472921e+06
90            106     96         107                1.471529e+06
95         101                1.471381e+06
91            106     96         102                1.467898e+06
107                1.461706e+06
90            106     95         107                1.444866e+06
96         101                1.440215e+06``````

Stoploss for both and long positions of about 96% (if the price goes below 4% of the buy price close the position) and for short positions of about 101 (meaning if the price raises above 1% sell price close the position). Here is the heatmap of the entire combinations. We are interested in the yellow zones. 107% stoploss short seems interesting too.

Let’s backtest another slice from the data using these optimized values. Let’s see how well the optimized strategy performed:

``````Start                     2021-03-01 00:00:00
End                       2021-05-05 23:55:00
Duration                     65 days 23:55:00
Exposure Time [%]                   76.824328
Equity Final [\$]                1543820.74068
Equity Peak [\$]                 1687013.50036
Return [%]                          54.382074
Buy & Hold Return [%]               27.703443
Return (Ann.) [%]                  1004.07315
Volatility (Ann.) [%]               649.99618
Sharpe Ratio                         1.544737
Sortino Ratio                       33.275677
Calmar Ratio                         64.78734
Max. Drawdown [%]                  -15.497984
Avg. Drawdown [%]                    -1.18527
Max. Drawdown Duration       29 days 23:00:00
Avg. Drawdown Duration        0 days 11:13:00
Win Rate [%]                        38.709677
Max. Trade Duration          11 days 10:30:00
Avg. Trade Duration           1 days 15:11:00
Profit Factor                        2.238145
Expectancy [%]                       1.562159
SQN                                  1.607989``````

It looks like we doubled the buy and hold return, despite having only a 38% winning rate. The number of trades is 31, one third of the original one. But we need to realize that the original idea was a scalping method. The optimized one is really using longer trends. Now we will test the two month period one year ago (01/March/2020 to 05/May/2020). Does this optimized strategy work in another time? Here are the results:

``````Start                     2020-03-01 00:00:00
End                       2020-05-05 23:55:00
Duration                     65 days 23:55:00
Exposure Time [%]                   60.925545
Equity Final [\$]                 1400231.5826
Equity Peak [\$]                 1441637.99534
Return [%]                          40.023158
Buy & Hold Return [%]                3.452817
Return (Ann.) [%]                  543.471889
Volatility (Ann.) [%]               563.50157
Sharpe Ratio                         0.964455
Sortino Ratio                       14.899343
Calmar Ratio                        21.705887
Max. Drawdown [%]                  -25.037995
Avg. Drawdown [%]                    -3.22443
Max. Drawdown Duration       44 days 23:50:00
Avg. Drawdown Duration        2 days 04:59:00
Win Rate [%]                        29.545455
Max. Trade Duration           6 days 12:00:00
Avg. Trade Duration           0 days 21:54:00
Profit Factor                        1.673854
Expectancy [%]                       0.870647
SQN                                  1.111204``````

Surprisingly the optimized strategy worked well within this other period. Although the percentage of winning trades are only about 30%, the returns look well. But I’m not satisfied. Let’s check a longer period. From 01/February/2018 to 05/May/2021. Here’s what the results look like:

``````Start                     2018-02-01 00:00:00
End                       2021-05-05 23:55:00
Duration                   1189 days 23:55:00
Exposure Time [%]                   79.531899
Equity Final [\$]                3160070.43656
Equity Peak [\$]                 3456734.54776
Return [%]                         216.007044
Buy & Hold Return [%]              473.427186
Return (Ann.) [%]                   42.320786
Volatility (Ann.) [%]               92.952654
Sharpe Ratio                         0.455294
Sortino Ratio                        1.165405
Calmar Ratio                         0.796827
Max. Drawdown [%]                  -53.111637
Avg. Drawdown [%]                   -2.476725
Max. Drawdown Duration      544 days 07:25:00
Avg. Drawdown Duration        4 days 17:55:00
Win Rate [%]                        25.490196
Max. Trade Duration          30 days 05:25:00
Avg. Trade Duration           1 days 13:03:00
Profit Factor                        1.181788
Expectancy [%]                       0.280834
SQN                                  1.344469``````

At least we are not loosing money. In 39 months we made 612 trades with a quarter winning trade rate. We still made about half of buy and hold and we were exposed to risk about 80% of the time. I think this optimized strategy looks promising. But remember backtesting results are not very reliable. Here’s how the chart looks like:

As promised here’s the complete python code. I have the data in a SQLite database, you need to get your own data.

``````import sqlite3 as sql
import pandas as pd
import numpy as np
import talib as talib
from datetime import datetime
from datetime import timedelta
from backtesting import Strategy, Backtest
from backtesting.lib import resample_apply
from matplotlib import pyplot as plt
import seaborn as sns
from findiff import FinDiff

dbfile = 'bitcoin.db'
table = 'bitcoin_5minute_raw'
conn = sql.connect(dbfile)

start_date = '2021-05-05'
how_many_months = "-2"
SQL = "SELECT DISTINCT Date,Open,Close,Low,High,Volume_USD FROM " + table + " WHERE Date < date('"+ start_date +"') and Date > date('"+ start_date+"','start of month','"+how_many_months+" month') ORDER BY Date"

data['Date'] = pd.to_datetime(data['Date'])
data.set_index("Date", inplace = True)
data.columns = ['Open','Close','Low','High','Volume'];

## Three indicators two time frames
# WMA(144),  SMA(5)
## hourly chart to look for direction of the trend
# SMA(5) < WMA(144) downtrend
# SMA(5) > WMA(144) uptrend
## 5 minute chart to make entries
# SMA(5) < WMA(144) downtrend
# SMA(5) > WMA(144) uptrend

class System(Strategy):
n1 = 5
n2 = 144
level = 20
profit = 106
profit_short = 91
stop_loss = 95
long_short = 1
level_short = 80
stop_loss_short = 101
sell_price = 0

def init(self):
# Compute moving averages the strategy demands
self.sma5 = self.I(talib.SMA, self.data.Close, self.n1)
self.wma144 = self.I(talib.WMA, self.data.Close, self.n2)
self.slowk,self.slowd = self.I(talib.STOCH,self.data.High,self.data.Low,self.data.Close)
self.hsma5 = resample_apply('H', talib.SMA, self.data.Close, self.n1)
self.hwma144 = resample_apply('H', talib.WMA, self.data.Close, self.n2)
# we will use this later with another stoploss strategy

def next(self):
price = self.data.Close[-1]
# If we don't already have a position, and
# if all conditions are satisfied, enter long.
if (not self.position and
self.slowk[-1] < self.level and
self.slowd[-1] < self.level and
self.slowk[-1] > self.slowd[-1] and
self.sma5[-1] > self.wma144[-1] and
self.hsma5[-1] > self.hwma144[-1]):
self.long_short = 1

# If the price closes at our profit target
# close the position, if any.
elif (price > self.buy_price*self.profit/100 and self.long_short == 1):
self.position.close()
self.long_short = 0

elif (not self.position and
self.slowk[-1] > self.level_short and
self.slowd[-1] > self.level_short and
self.slowk[-1] > self.slowd[-1] and
self.sma5[-1] < self.wma144[-1] and
self.hsma5[-1] < self.hwma144[-1]):
self.sell(sl=self.stop_loss_short*price/100)
self.long_short = 2
self.sell_price = price

# If the price closes at our profit target
# close the position, if any.
elif (price < self.sell_price*self.profit_short/100 and self.long_short == 2):
#elif (price > self.profit_short/100 * self.sma5[-1] and self.long_short == 2):
#elif (price < price + 1.5*self.n_atr*self.atr[-1] and self.long_short == 2):
self.position.close()
self.long_short = 0
self.sell_price = 0

bt = Backtest(data, System, commission=.002, exclusive_orders=True, cash=1000000)
output = bt.run()
print(output)
bt.plot()
# Optimization code
'''
stats, heatmap = bt.optimize(profit_short = range(90,99,1), profit = range(101,110,1), stop_loss=range(90,99,1),
stop_loss_short=range(101,110,1),  maximize='Equity Final [\$]',return_heatmap=True)
print(stats)
print(stats._strategy)
hm = heatmap.groupby(['profit', 'profit_short','stop_loss','stop_loss_short']).mean().unstack()
print(heatmap.sort_values(ascending=False).iloc[:10])
plt.figure(figsize=(12, 10))
sns.heatmap(hm[::-1], cmap='viridis')
plt.savefig('foo.png')
bt.plot()
'''``````

## Concluding Thoughts

The entry part of this strategy is clear. However, the exit is more difficult. We saw that when optimized the SMA+WMA+Stochastic strategy appeared to be working OK. However, its efficiency changed depending on the time we tested it. Will it work in the coming days? It needs to be tested. Also we learned that win rate is not necessarily the best metric, other metrics such as return percentage and Sharpe ratio could be used. Again let me remind this is not trading or investment advice. You should always remember backtesting results may be unreliable. Overfitting is always present to a degree.

## References

This site uses Akismet to reduce spam. Learn how your comment data is processed.