How Data Science Takes the Guesswork out of Trading Decision Making

mastermindankur
DBS Tech Blog
Published in
8 min readAug 13, 2021

If you’re standing on the edge of a lake trying to find out how deep it is, you wouldn’t jump in with both feet to test it out. A more prudent decision would be to put a long stick into the lake to find out just how far down it goes. Using the same analogy, you wouldn’t commit to a new trading strategy without first testing the waters (so to speak), at the risk of losing your hard-earned money, particularly if you aren’t an experienced trader to begin with. So, what are some strategies you can use to aid complex decision-making?

Past Experience Is Invaluable For Complex Decision Making

Photo by Javier Allegue Barros on Unsplash

You are probably already using past experiences to make new decisions in your everyday life. And research has shown that this is useful in making complex decisions, particularly when the information you have on hand is uncertain or confusing. Our experiences change the circuitry in our brains, allowing us to quickly categorise what we see and act accordingly.

However, if you’re completely new to an activity like trading, how do you develop or gain this experience without prior knowledge? One of the ways to do this is to run your strategy on historic data to gauge its performance — also known as back-testing. A huge advantage of this method is that it allows you to test your hypothesis without putting in real money, so you can tweak it until you’re confident that you can execute an optimised trading strategy.

Now, I will back-test a very common strategy which is based on the ideas of Support and Resistance, where you’ll see how this method can be accomplished with a basic understanding of Python (or any programming language) and some commonly used data science libraries. But first, a quick summary of what Support and Resistance mean?

The Support

As the name suggests, Support is the price at which the prices of the stock tends to hold. It is also generally the price point at which the price tends to bounce back. The demand tends to increase at this price — there are more buyers than sellers and the price tends to reverse. The support is one of the critical technical level market participants look for in a falling market. The support often acts as a trigger to buy.

The Resistance

As the name suggests Resistance is the price point where the price of the stock is not expected to move further. The Resistance price is above the market price of the stock. Resistance is also the point at which the price starts to drop again. The resistance is one of the critical technical analysis tools which market participants look at in a rising market. The resistance often acts as a trigger to sell.

Since the price of stock tends to stop and reverse at these points, as a trader you would see an opportunity to buy near the support levels and sell near the resistance levels. Depending on the time window you want to enter the market, you would want to compute your support and resistance levels for that time frame. There are a few famous techniques used by traders to compute the Support and Resistance levels, including Classic, Fibonacci, Camarilla and Woodie. For the purpose of this article, we will look at the Classical way of computation.

Classical Way of Pivot Point Calculation

Pivot point (PP) = (High + Low + Close) / 3.

First resistance (R1) = (2 x PP) — Low.

First support (S1) = (2 x PP) — High.

Second resistance (R2) = PP + (High — Low)

Second support (S2) = PP — (High — Low)

Third resistance (R3) = High + 2(PP — Low)

Third support (S3) = Low — 2(High — PP)

Let us try to “back-test” the following trading strategy for an intra-day trader, one who buys and sells stocks within the same trading day.

1 Buy just above the Support Level

2 Sell just a little below the Resistance Level

Ok let us get back-test this strategy, importing the necessary libraries.

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import matplotlib.dates as dates
import quandl
%matplotlib inline

I am using Quandl API for this example to pull the stock prices listed on Bombay Stock Exchange. This call retrieves data from 01 Jan, 2021 to Mar 14, 2021 for BSE/BOM500112. The stock in consideration is of SBI and its code is 500112.

quandl.ApiConfig.api_key = 'your_own_key'
#Get SBI stock prices for a date range
sbi =quandl.get('BSE/BOM500112', start_date='2021-01-01', end_date='2021-03-14')

The below code evaluates the Pivot Point, Support and Resistance Level as per the classical way.

sbi['PP']= (sbi['High']+sbi['Low']+sbi['Close'])/3
sbi['R1']= 2*sbi['PP'] -sbi['Low']
sbi['S1']= 2*sbi['PP'] -sbi['High']
sbi['R2']= sbi['PP'] + (sbi['High'] - sbi['Low'])
sbi['S2']= sbi['PP'] - (sbi['High'] - sbi['Low'])
sbi['R3']= sbi['High'] + 2*(sbi['PP'] - sbi['Low'])
sbi['S3']= sbi['Low'] - 2*(sbi['High'] - sbi['PP'])

Instead of executing the trade exactly at the Support and Resistance levels, let us try to buy a little higher than the Support level and sell a little lower that the Resistance level. But how do we decide what these “slightly higher” and “slightly lower” ticks should be? Most stocks tend to trade in a specific range during a day. We would look at this range — the price difference between the highest price to the lower price for a specific day — and calculate the median of the range over a certain time period, and consider 10% of this as our tick value. Why am I calculating these up and down ticks ? To increase the probability of getting the trade.

# Up and Down are the ticks above and below which we want to execute up= sbi['Spread H-L'].median()*.10
down= sbi['Spread H-L'].median() *.10

Great, now set our Target prices.

sbi['Buy']= sbi['S1'].shift(1) + up
sbi['Sell']= sbi['R1'].shift(1) - down

To determine if we were able to execute the trade, we need to look at three possibilities. I am using a flag called ‘got_it’. Depending upon the three possibilities that can happen, I am setting the value of the flag ‘got_it’. One underlying assumption we are making is that the support price hits first before the resistance price, meaning we will buy first and sell later.

1 — If we are able to buy at Support+delta and sell at Resistance-delta the same day, it is a successful Trade.

2 — If we are able to Buy at Support+delta but are not able to sell it since the Resistance-delta price never came, I would still want to square off my position at the end of the day. I am forced to sell it at the closing price, regardless of whether I am in the money or out of the money.

0 — If we are not able to buy at all since the Support+delta price was never reached that day, the trade did not happen.

# Set initial value set to 0 of all elements
sbi['got_it'] = 0

# if the trade happened between support and resistance levels, put 1 in got_it column
sbi.loc[(sbi['Buy']>sbi['Low']) & (sbi['Sell'] <sbi['High']) & (sbi['Sell']>sbi['Buy']),'got_it']=1

# If I was able to Buy but not able to sell it becuase price did not hit resistance level, put 2 in got_it column
sbi.loc[(sbi['Buy']>sbi['Low']) & (sbi['Sell'] >sbi['High']) ,'got_it']=2

Now let us compute the profits we earned, when the Resistance level was reached the same day and the trade happened successfully:

Profit = Selling Price — Buying Price

However, when the Resistance price was not reached, we are forced to sell at the closing price for that day. In that case:

Profit (or Loss) = Closing Price — Buying Price

sbi['Profit']=0
profit= sbi['Sell']-sbi['Buy']
forced_profit_or_loss= sbi['Close']-sbi['Buy']

sbi.loc[(sbi['got_it']==1) ,'Profit']=profit
sbi.loc[(sbi['got_it']==2) ,'Profit']=forced_profit_or_loss

Great, I have been able to compute the profit or Forced Profit or Loss. Let me understand in the date range of interest— how many days was I able to execute a Successful Trade OR Forced Square off OR No trade.

sbi['got_it'].plot.hist(label='Labels: 0= No Trade, 1 = Succesfull Trade, 2 = Squaredoff Trade', figsize=(12,10))
plt.ylabel('# of Trades')
plt.xlabel('Trade Status')
plt.xticks([0,1,2])
plt.style.use('ggplot')
plt.legend()
For the Date Range, finding if we were able to execute the trade, squared off forcefully or trade did not happen

Out of the 33 trading days between 1 Jan 2021 to 14 March 2021, we would have gotten successful trades on 25 days, done a square-off on 12 days and no trade would have been possible on 12 days.

Now let us look at the net profit or loss using this strategy in the 2.5 month period.

x=sbi['Profit'].sum()/sbi['Open'].mean() *100
print("The profit percentage you can get is {rate}".format(rate=x))
The profit percentage you can get is 4.66 %

Let us have a look visually — what was the band that was formed and whether we were able to get the trade or not.

sbi[['High','Low','Buy','Sell']].tail(30).plot(figsize=(20,15))
plt.ylabel('SBI Price')
plt.xlabel('Trading Date')
plt.style.use('ggplot')
plt.legend()

Top Performing Stocks in BSE 100 List Using this Strategy:

In the above example, if we had executed this strategy on SBI, we would have gotten a return of 4.66%. What if we wanted to back-test this on all the top 100 stocks listed on BSE and compare their returns? We would run this strategy on every stock, calculate the return and sort it in descending order of returns. Here is the analysis of the TOP 100 stocks by Market Capitalisation for the time period 1 Jan 2021 to 14 March 2021.

If you end up iterating through the 100 BSE stocks, you should end up getting the following returns:

Return of Support Resistance Strategy on Top 100 BSE Companies by Market Capitalisation

If you had invested in Siemens Ltd daily using this strategy, it would have helped you grow your principal by 36%, while ADANI ENTERPRISES LTD would have given you a return of 29%.

Conclusion and Key takeaways:

  1. Back-testing is a secret weapon in trading because it lets you test your hypothesis without putting in real dollars, allowing you tweak your strategy multiple times before you execute your optimised strategy in the market.
  2. Since the price of the stock tends to stop and reverse at these points, as a trader you will see an opportunity to buy near the support levels and sell near the resistance levels.
  3. As an investor you should test the waters, before putting both your feet in it.

Github Repository Link:

https://github.com/mastermindankur/stock-analysis/

--

--

DBS Tech Blog
DBS Tech Blog

Published in DBS Tech Blog

Best Bank for a Better World — hear it from the Engineers who build it

mastermindankur
mastermindankur

Written by mastermindankur

Proud Indian. Everyone can innovate via the power of compounding over time — a little progress every day adds upto BIG results.

Responses (9)