Profitable Trading Strategy using Python

Profitable Trading Strategy using Python

Investing Strategy

Introduction

An investor may apply hundreds, if not thousands, of trading strategies to generate profits. Each strategy is based on a variety of factors, including the investor's goals, risk appetite, age, capital, and so on. Based on these factors, an investor may make an informed decision and select the strategy that best suits his or her goals.

In this blog, we will use Python to backtest one of the most basic investing strategies which may have the potential to generate significant returns. We will apply this strategy to a stock - Tata Consultancy Services (TCS), India's largest IT company, and let's see the results. Feel free to try this strategy with the stock of your liking.

The Strategy

The basic investing strategy consists of the following rules:

  1. Buy a particular number of shares only when the price of the asset falls less than or equal to 2% in a day.
  2. Sell all the shares only when the price of the asset rises greater than or equal to 3% in a day.

Libraries Used

The libraries used in this project make it extremely simple to analyze your data. Installing these libraries is done using the pip command in the terminal:

pip install library_name

The libraries used are briefly described below:

  • Pandas - To easily manipulate data in a data frame
  • Numpy - To visualize your data
  • Matplotlib - To make numerical calculations within a grouped data simple
  • Yfinance - To extract data from Yahoo Finance.

Let's begin coding

Importing Libraries

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import yfinance as yf

Extracting Data

asset=yf.Ticker("TCS.NS") #setting our stock as TCS (1)
hist = asset.history(start="2021-01-01")['Close'] #return type series (2)
df=pd.DataFrame(hist) #Converting series to dataframe #(3)
df.head() #viewing first 5 rows of dataframe (4)

● new_buy_dup.ipynb - Projects - Visual Studio Code 02-09-2022 15_38_17.png

While entering the stock ticker, keep in mind since we are using the Yahoo Finance API, we are required to enter the stock ticker from the yahoo finance website. For whichever stock or asset you choose, remember to take the asset's ticker from the yahoo finance website.

Code Explanation:

  1. Specify the asset ticker in order for Yahoo Finance API to give us our respective asset data.
  2. Extracting asset closing price from 1st January 2021.
  3. In step 2, the return type of the data in series. Hence we converted this series datatype into a data frame.
  4. Printing the first 5 rows, to get a brief overview of the data present.

To know about the Yfinance API, click here.

Data Manipulation

In this section, we will create a new column "Percent Change" which will store the daily price change of the asset.

df['Percent Change']=(df['Close'].pct_change())*100
df.head()

● new_buy_dup.ipynb - Projects - Visual Studio Code 02-09-2022 15_38_47.png We can notice an extra column Percent Change has been created which stores the daily price percent change of the asset.

Data Cleaning

Null Values

df.isna().sum().sum()

The output for our above code is 1. This indicates, that in our dataset, we have 1 null value present. Hence, we need to get rid of this null value (below).

The Null value was caused due the pct_change() function.

df.dropna(inplace=True)

The above function, drops all the rows in the data frame which has null values.

Duplicate Values

df.duplicated().sum()

The output for our above code is 0. This indicates, that in our dataset, we have no duplicate values.

Datatypes

df.dtypes

● new_buy_dup.ipynb - Projects - Visual Studio Code 02-09-2022 15_39_38.png

The above function returns the datatype of each column in our data frame. We can notice, that each column of our dataset is of the appropriate type.

df.head()

● new_buy_dup.ipynb - Projects - Visual Studio Code 02-09-2022 15_38_28.png

Our data frame is free of errors, hence we can now begin our analysis.

Analysis

Buy or Sell?

When do we buy or sell the asset? As discussed in the Strategy section, we will use the following code to indicate when to Buy or Sell the asset.

df['Transaction']="" #(1)

for i in range(len(df)): #(2)
    if df['Percent Change'].iloc[i]<=-2:  #(3)
        df['Transaction'].iloc[i]="Buy" 
    elif df['Percent Change'].iloc[i]>=3: #(4)
            df['Transaction'].iloc[i]="Sell" 
    else: 
        df['Transaction'].iloc[i]="None"  #(5)

Code Explanation:

  1. Creation of an extra column Transaction to store the operation (Buy, Sell, None) to be performed.
  2. Looping through our data frame to check If the price of our asset falls less than or equal to 2% in a day or rises greater than or equal to 3% in a day.
  3. If our asset price falls less than or equal to 2% in a day, we Buy the asset. Hence in the transaction column, we assign the value as "Buy".
  4. If the price of the asset rises greater than or equal to 3% in a day, we will Sell the asset. Hence in the transaction column, we assign the value as "Sell".
  5. If none of the above scenarios take place, we assign the Transaction column value as "None".

Extracting Buying and Selling Data

In this section, we will store the dates of when we buy, and sell and also the buying price of the respective asset.

Buying_Dates=[] #stores buying date of the asset
Selling_Dates=[] #stores selling date of the asset
Buying_Price=[] #stores buying price of the asset

for i in range(len(df)): #(1)
    if "Buy" in df['Transaction'].iloc[i]: #Finding "Buy" in *Transaction* column #(2)
        Buying_Dates.append(df.iloc[i+1].name)
        Buying_Price.append(df['Close'].iloc[i])
    if "Sell" in df['Transaction'].iloc[i]: #Finding "Sell" in *Transaction* column #(3)
        Selling_Dates.append(df.iloc[i+1].name)

Code Explanation:

  1. We loop through the data frame Transaction column to find if "Buy" and "Sell" is present.
  2. If "Buy" is present within the Transaction column, we will append the corresponding date to the Buying_Dates list as well as append the corresponding asset price to the Buying_Price list.
  3. If "Sell" is present within the Transaction column, we will append the corresponding date to the Selling_Dates list.

Plotting Buy and Sell Signals

plt.figure(figsize=(30,8))
plt.scatter(df.loc[Buying_Dates].index, df.loc[Buying_Dates]['Close'],marker='^',c='g')
plt.scatter(df.loc[Selling_Dates].index, df.loc[Selling_Dates]['Close'],marker='*',c='r')

plt.plot(df['Close'], alpha=0.7)

plt.title("Tata Consultancy Services")
plt.ylabel("Price (Rs)")
plt.xlabel("Date")

Plots - Projects - Visual Studio Code 02-09-2022 19_29_27.png The green marker (^) refers to the times when we buy the asset whereas the red marker (*) refers to the times we sell our asset.

Strategy Results

Calculating Profit & Loss

investment_amount=2*asset.info['regularMarketPrice'] 
invest=[] #amount invested
pnl=[] #profit or loss
qty=0 #number of shares
amt=0 #total investment

for i in range(len(df)): # (1)
    if "Buy" in df['Transaction'].iloc[i]: # (2)
        qty=qty+(investment_amount/df['Close'].iloc[i]) #qty (3)
        amt=amt+investment_amount
    if(qty>0): #(4)
        if "Sell" in df['Transaction'].iloc[i]: 
            invest.append(amt) #(5)
            pnl.append((df['Close'].iloc[i]*qty)-amt) #(6)
            qty=0 #(7)
            amt=0

The first line of code investment_amount=2asset.info['regularMarketPrice'], is the amount we wish to invest. 2 refers to the number of shares we are buying, and the asset.info['regularMarketPrice']* function returns us the current price of the stock. Hence the product of asset price and shares gives us our investment amount.

Code Explanation:

  1. In the loop, we will first go through the Transaction column of our data frame.
  2. If "Buy" is present in the Transaction column we will calculate the number of shares.
  3. We will calculate the investment amount
  4. Only if the number of shares is greater than 0, we will search for "Sell" in the Transaction column (The number of shares has to be greater than 0 to sell).
  5. Append the investment amount to the invest list.
  6. Append the profit and loss in pnl list (Calculation for pnl is done in the brackets - (df['Close'].iloc[i]qty)-amt)* i.e Current Price - Invested Price).
  7. Since we sold all of our shares, assign qty=0 and amt=0.

Result Dataframe

In this part, we will convert our strategy results into a data frame for easy viewing and getting further results.

invest=np.array(invest) #(1)
pnl=np.array(pnl)

roi_arr=pnl/invest #(2)

result_df=pd.DataFrame() #Data Frame creation (3)
result_df["Investment Amount"]=invest # (4)
result_df["Profit/loss"]=pnl
result_df["ROI"]=roi_arr*100

Code Explanation:

  1. Converting investment amount (invest) and profit or loss (pnl) lists to NumPy array for easy manipulation of data.
  2. Calculating Return on Investment (Profit_Loss of Investment / Amount Invested).
  3. Creation of data frame.
  4. Giving our data frame values.

Printing Dataframe and Results

print(result_df)

● new_buy_dup.ipynb - Projects - Visual Studio Code 03-09-2022 10_58_51.png

The total gain implementing this strategy is 2356 (print("Total Profit and Loss",sum(pnl)))

Result Analysis

result_df.describe()

● new_buy_dup.ipynb - Projects - Visual Studio Code 02-09-2022 15_40_08.png

We can view the statistical results of our strategy's results. We notice the maximum loss we have incurred is -2% and the maximum gain we have generated is 11%.

plt.figure(figsize=(10,7))
result_df.boxplot(["Profit/loss"])

Plots - Projects - Visual Studio Code 02-09-2022 19_30_49.png

Testing Strategy on a number of stocks

I tried the same strategy on some of Tata stocks including:

  • Tata Consultancy Services (TCS)
  • Tata Motors
  • Tata Steel
  • Tata Elxsi
  • Tata Chemicals
  • Tata Power

The results are as follows:

● new_buy_dup.ipynb - Projects - Visual Studio Code 02-09-2022 15_40_34.png

Plots - Projects - Visual Studio Code 02-09-2022 19_29_38.png

Plots - Projects - Visual Studio Code 02-09-2022 19_29_31.png

Conclusion

We have now seen the potential returns of implementing this strategy with a number of stocks. We can conclude by saying that this strategy is a low-risk strategy. Thus, it is ideal for Conservative and Moderate investors. However, this strategy is NOT financial advice; all work done here is entirely for educational purposes. Before investing, an investor should perform their own research. An investor may combine this strategy with other strategies to achieve even greater results.

Furthermore, feel free to try this code with a number of different stocks and different timeframes. You may also increase the number of shares purchased each time to 10, 15, or 20.. and may also increase the daily percentage change to maybe -5% to "Buy" the asset and +5% to "Sell" the asset. For example, you may buy 20 shares of a particular stock when the daily percentage change falls below 5% and sell when the daily percentage change rises 5%.

Bonus Tip! - You could also try implementing this strategy using cryptocurrencies. But, keep in mind cryptocurrencies are volatile hence keep the daily percentage change values >=5.

Please feel free to share your results in the comments below.

Key Takeaways

  • This is a "Basic Investing Strategy". We have tested this strategy on TCS stock.
  • Data Analytics concepts involved - Data Cleaning, Data Manipulation, Data Extraction, Data Visualization, and Analysis.
  • We have gathered data using Yfinance API.
  • We have plotted our buying and selling signals using a scatter plot.
  • For TCS, this strategy yields us a profit of ~Rs 2300.
  • The maximum loss we have incurred is -2% and the maximum gain we have generated is 11% using this strategy for TCS.
  • Out of all the Tata stocks compared, this strategy gave the highest ROI when implemented with Tata Power.
  • This strategy is ideal for Conservative and Moderate investors.
  • This is NOT FINANCIAL ADVICE.

Please feel free to connect with me and ask for any investment strategy or analysis you would like me to perform. If you enjoyed my article and found it informative please follow and comment below. Thank you for your time.