FabTrader_Logo_Main
  • Home
  • Courses
    • Build Algo Trading Platform using Python Course
  • Store
  • Tools
  • Stories
  • About Me
Edit Content
FabTrader_Logo_Main
Welcome to FabTrader Community!

Course Dashboard
Store Account
Cart
Algo Trading Course
Other Courses
About Me
Store
Stories

Get in touch with me

hello@fabtrader.in

blog banner background shape images
  • FabTrader
  • March 25, 2025

Zero Loss Strategy by Mahesh Chander Kaushik – Backtested!

  • 13 min read
  • 389 Views
Introduction

Intraday trading strategies come and go, but only a few stand the test of time. One such strategy is the Zero Loss Intraday Strategy proposed by Mahesh Chander Kaushik, a well-known YouTuber renowned for his simple yet effective trading methods. I recently created a YouTube video backtesting this strategy using Python, and in this article, I’ll walk you through its rules, the backtesting results, and whether it holds up in the real market

Strategy Overview

  • Original Proposer: Mahesh Chander Kaushik
  • Type: Intraday – Pivot Range Breakout Strategy
  • Time Frame: 5-minute Candles
  • Trade Direction: Long and Short Only
  • Indicators Used: Custom Indicator (Pivot Price Point)
  • Product Type: Cash Segment
  • Stock Universe: Top 10 Market Cap Stocks Only

Pivot Price Calculation Logic

A key aspect of this strategy is the calculation of the Pivot Price, which is determined at 11 AM each trading day using the formula:

Pivot Price Point = ( Yesterday’s Day Close + Today’s Intraday High + Today’s Intraday Low) / 3

At 11 AM:

  • If the CMP < Pivot Price, a Short Trade is considered, but with additional conditions.
  • If the Current Market Price (CMP) > Pivot Price, a Long Trade is initiated.

Strategy Rules for Long Trades

Entry Conditions (at 11 AM):
  • If CMP is greater than the Pivot Price, take a long position.
Risk Management / Position Sizing:
  • Limit position size to Rs.10,000 per order.
  • The original strategy advises a total capital allocation of Rs.500,000 per stock.
Exit Conditions:

If the target is not met intraday, take delivery of the stock for a longer-term hold.

The target is an intraday gain of 0.7% (excluding brokerage and fees).

No stop-loss is placed.

Strategy Rules for Short Trades

Entry Conditions (at 11 AM):
  • CMP is less than the Pivot Price.
  • There are existing holdings of the stock.
  • The overall profit position of the existing holdings for that stock is greater than 0.7%.
Risk Management / Position Sizing:
  • Limit position size to Rs.10,000 per order.
  • The original strategy suggests Rs.500,000 capital per stock.
Exit Conditions:
  • The target is an intraday profit of 0.7% (excluding brokerage and fees).
  • Stop-loss is set at the intraday high.
  • If the target is not met, take delivery by selling from existing holdings. The loss from the trade is covered by the previous profit in holdings.
# ------------------------------------------------------------------------------------
#                          FabTrader Algorithmic Backtesting
# ------------------------------------------------------------------------------------
# Copyright (c) 2022 FabTrader (Unit of Rough Sketch Company)
#
# LICENSE: PROPRIETARY SOFTWARE
# - This software is the exclusive property of FabTrader.
# - Unauthorized copying, modification, distribution, or use is strictly prohibited.
# - Written permission from the author is required for any use beyond personal,
#   non-commercial purposes.
#
# CONTACT:
# - Website: https://fabtrader.in
# - Email: fabtraderinc@gmail.com
#
# Usage: Internal use only. Not for commercial redistribution.
# Permissions and licensing inquiries should be directed to the contact email.

import pandas as pd
import datetime as dt

import BrokerConnector
from Symbol_master import Instruments


class ZeroLossStrategyBacktest:
    def __init__(self, stocks, start_date, end_date, use_stoploss=True, target_pct=0.0075,
                 max_investment=10000, starting_portfolio_value=100000):
        self.stocks = stocks
        self.start_date = start_date
        self.end_date = end_date
        self.use_stoploss = use_stoploss
        self.target_pct = target_pct
        self.max_investment = max_investment
        self.portfolio_value = starting_portfolio_value
        self.trade_log = []

    def get_previous_trading_day_close(self, stock, current_date):
        """Find the previous valid trading day’s closing price."""

        # >> Replace this code with your own function to retrieve historic candlestick data << #
        daily_data = Instruments.get_historical_data(stock, self.start_date, self.end_date)
        # >> Replace this code with your own function to retrieve historic candlestick data << #

        daily_data = daily_data.sort_index()
        previous_dates = daily_data.index[daily_data.index < current_date]

        if len(previous_dates) > 0:
            prev_day = previous_dates[-1]
            return daily_data.loc[prev_day]["Close"]
        return None

    def get_high_low_for_the_day(self, stock, current_date):
        """Get high & low from 5-minute data before 11 AM."""
        curr_date = current_date.date()

        # >> Replace this code with your own function to retrieve historic candlestick data << #
        intraday_data = Instruments.get_historical_data(stock, curr_date, curr_date, "5minute")
        # >> Replace this code with your own function to retrieve historic candlestick data << #

        if intraday_data.empty:
            return None, None, None, None

        intraday_data_before_11am = intraday_data[intraday_data.index.time < pd.Timestamp("11:00").time()]
        if intraday_data_before_11am.empty:
            return None, None, None, None

        intraday_data_after_11am = intraday_data[intraday_data.index.time >= pd.Timestamp("11:00").time()]
        if intraday_data_after_11am.empty:
            return None, None, None, None

        return (intraday_data_before_11am["High"].max(), intraday_data_before_11am["Low"].min(),
                intraday_data_after_11am["High"].max(), intraday_data_after_11am["Low"].min(),
                intraday_data_after_11am.iloc[0]['Close'], intraday_data_after_11am.iloc[-1]['Close'])


    def backtest(self):
        """Runs the backtest for positional trades."""
        for stock in self.stocks:
            print(f"Backtesting {stock}...")

            # >> Replace this code with your own function to retrieve historic candlestick data << #
            data = Instruments.get_historical_data(stock, self.start_date, self.end_date)
            # >> Replace this code with your own function to retrieve historic candlestick data << #

            data.to_csv(stock+'.csv')
            if data.empty:
                continue

            data = data.sort_index()

            for date, row in data.iterrows():
                prev_close = self.get_previous_trading_day_close(stock, pd.Timestamp(date))
                if prev_close is None:
                    continue

                high_before_11am, low_before_11am, high_after_11am, low_after_11am, close_at_11am, close_at_eod = (
                    self.get_high_low_for_the_day(stock, date))
                if high_before_11am is None or low_before_11am is None:
                    continue

                pivot_level = (prev_close + high_before_11am + low_before_11am) / 3

                if close_at_11am >= pivot_level:  # Bullish Zone. Long Trade
                    qty = self.max_investment // close_at_11am
                    target = close_at_11am * (1 + self.target_pct)
                    if target <= high_after_11am:
                        # Target hit intraday
                        pnl = (target - close_at_11am) * qty
                        pnl_percentage = (pnl * 100) / (close_at_11am * qty)
                        brokerage = 10 + (target * qty) * 0.0012
                        net_pnl = pnl - brokerage
                        net_pnl_percentage = (net_pnl * 100) / (close_at_11am * qty)

                        self.trade_log.append({
                            "tradingSymbol": stock,
                            "tradeState": "completed",
                            "entry_date": date,
                            "direction": "Long",
                            "qty": qty,
                            "entry": close_at_11am,
                            "exit": 0.0,
                            "Target": target,
                            "StopLoss": low_before_11am,
                            "exit_date": date.date(),
                            "pnl": pnl,
                            "pnl%": pnl_percentage,
                            "brokerage": brokerage,
                            "netPnl": net_pnl,
                            "netPnl%": net_pnl_percentage,
                            "Trade Status": "Target Hit"
                        })
                        self.portfolio_value += net_pnl
                    else:
                        # Trades that were not closed the same day will be carried over
                        self.trade_log.append({
                            "tradingSymbol": stock,
                            "tradeState": "active",
                            "entry_date": date,
                            "direction": "Long",
                            "qty": qty,
                            "entry": close_at_11am,
                            "Target": target,
                            "StopLoss": 0.0,
                            'exit_date': None,
                            'exit': 0.0,
                            "pnl": 0,
                            "pnl%": 0,
                            "brokerage": 0.0,
                            "netPnl": 0.0,
                            "netPnl%": 0.0,
                            "Trade Status": "Open"
                        })

                elif close_at_11am <= pivot_level: # Bearish Zone. Short Trade
                    qty = self.max_investment // close_at_11am
                    target = close_at_11am * (1 - self.target_pct)
                    sl = high_before_11am
                    if target >= low_after_11am:
                        # Target hit intraday

                        pnl = (close_at_11am - target) * qty
                        pnl_percentage = (pnl * 100) / (close_at_11am * qty)
                        brokerage = 10 + (target * qty) * 0.0012
                        net_pnl = pnl - brokerage
                        net_pnl_percentage = (net_pnl * 100) / (close_at_11am * qty)

                        self.trade_log.append({
                            "tradingSymbol": stock,
                            "tradeState": "completed",
                            "entry_date": date,
                            "direction": "Short",
                            "qty": qty,
                            "entry": close_at_11am,
                            "exit": sl,
                            "Target": target,
                            "StopLoss": low_before_11am,
                            "exit_date": date.date(),
                            "pnl": pnl,
                            "pnl%": pnl_percentage,
                            "brokerage": brokerage,
                            "netPnl": net_pnl,
                            "netPnl%": net_pnl_percentage,
                            "Trade Status": "Target Hit"
                        })
                        # self.portfolio_value += (target - pivot_level) * qty
                        self.portfolio_value += net_pnl
                    elif sl <= high_after_11am:
                        # SL Hit Intraday

                        pnl = (close_at_11am - sl) * qty
                        pnl_percentage = (pnl * 100) / (close_at_11am * qty)
                        brokerage = 10 + (sl * qty) * 0.0012
                        net_pnl = pnl - brokerage
                        net_pnl_percentage = (net_pnl * 100) / (close_at_11am * qty)

                        self.trade_log.append({
                            "tradingSymbol": stock,
                            "tradeState": "completed",
                            "entry_date": date,
                            "direction": "Short",
                            "qty": qty,
                            "entry": close_at_11am,
                            "Target": target,
                            "StopLoss": low_before_11am,
                            'exit_date': date.date(),
                            'exit': sl,
                            "pnl": pnl,
                            "pnl%": pnl_percentage,
                            "brokerage": brokerage,
                            "netPnl": net_pnl,
                            "netPnl%": net_pnl_percentage,
                            "Trade Status": "SL Hit"
                        })
                        self.portfolio_value += net_pnl
                    else:
                        # For Short Trades, close the trade at EOD (profit or loss doesnt matter)
                        pnl = (close_at_11am - close_at_eod) * qty
                        pnl_percentage = (pnl * 100) / (close_at_11am * qty)
                        brokerage = 10 + (close_at_eod * qty) * 0.0012
                        net_pnl = pnl - brokerage
                        net_pnl_percentage = (net_pnl * 100) / (close_at_11am * qty)

                        self.trade_log.append({
                            "tradingSymbol": stock,
                            "tradeState": "completed",
                            "entry_date": date,
                            "direction": "Short",
                            "qty": qty,
                            "entry": close_at_11am,
                            "Target": target,
                            "StopLoss": high_before_11am,
                            'exit_date': date.date(),
                            'exit': close_at_eod,
                            "pnl": pnl,
                            "pnl%": pnl_percentage,
                            "brokerage": brokerage,
                            "netPnl": net_pnl,
                            "netPnl%": net_pnl_percentage,
                            "Trade Status": "Force Closed"
                        })
                        self.portfolio_value += net_pnl

            # For all carried over trades, check if target achieved later in the testing cycle
            for trade in self.trade_log:
                for date, row in data.iterrows():
                    last_close_price = row['Close']
                    if trade['Trade Status'] != "Open":
                        continue
                    if date < trade['entry_date']:
                        continue
                    if row['High'] > trade['Target']:
                        
                        pnl = (trade['Target'] - trade['entry']) * trade['qty']
                        pnl_percentage = (pnl * 100) / (trade['entry'] * trade['qty'])
                        brokerage = 10 + (trade['Target'] * trade['qty']) * 0.0012
                        net_pnl = pnl - brokerage
                        net_pnl_percentage = (net_pnl * 100) / (trade['entry'] * trade['qty'])
                        
                        trade['exit'] = trade['Target']
                        trade['exit_date'] = date.date()
                        trade['pnl'] = pnl
                        trade['pnl%'] = pnl_percentage
                        trade["Trade Status"] = "Target Hit"
                        trade["brokerage"] = brokerage
                        trade['netPnl'] = net_pnl
                        trade['netPnl%'] = net_pnl_percentage
                        trade["tradeState"] = "completed"
                        self.portfolio_value += net_pnl
                        break

            # Enable this code below to:
            #   Update latest price for all open trades so that notional profit/loss at the
            # end of backtesting can be calculated. All open trades will be force closed and
            # pnl will reflect the latest price at the end of the backtesting period
            # for trade in self.trade_log:
            #     if trade['Trade Status'] != "Open":
            #         continue
            #
            #     pnl = (last_close_price - trade['entry']) * trade['qty']
            #     pnl_percentage = (pnl * 100) / (trade['entry'] * trade['qty'])
            #     brokerage = 16 + (last_close_price * trade['qty']) * 0.0012
            #     net_pnl = pnl - brokerage
            #     net_pnl_percentage = (net_pnl * 100) / (trade['entry'] * trade['qty'])
            #
            #     trade['exit'] = last_close_price
            #     trade['exit_date'] = end_date
            #     trade['pnl'] = pnl
            #     trade['pnl%'] = pnl_percentage
            #     trade["brokerage"] = brokerage
            #     trade['netPnl'] = net_pnl
            #     trade['netPnl%'] = net_pnl_percentage
            #     trade["Trade Status"] = "Force Closed"
            #     trade["tradeState"] = "completed"
            #     self.portfolio_value += net_pnl_percentage

            #  Per original strategy, stoploss is optional and is applicable only for intraday
            #  Enable this code below if you would like to extend this to the entire backtest period
                    # if self.use_stoploss:
                    #     if date == trade['Buy Date']:
                    #         if row['Low'] < trade['StopLoss']:
                    #             pnl = (trade['StopLoss'] - trade['entry']) * trade['qty']
                    #             pnl_percentage = (trade['StopLoss'] - trade['entry']) * trade['qty']
                    #             brokerage = 16 + (trade['StopLoss'] * trade['qty']) * 0.0012
                    #             net_pnl = pnl - brokerage
                    #             net_pnl_percentage = (net_pnl * 100) / (trade['entry'] * trade['qty'])
                    #             trade['exit'] = trade['StopLoss']
                    #             trade['exit_date'] = date
                    #             trade['pnl'] = pnl
                    #             trade['pnl%'] = pnl_percentage
                    #             trade["brokerage"] = brokerage
                    #             trade['netPnl'] = net_pnl
                    #             trade['netPnl%'] = net_pnl_percentage
                    #             trade["Trade Status"] = "SL Hit"
                    #             self.portfolio_value += net_pnl_percentage
                    #             break

        self.generate_report()

    def generate_report(self):
        """Generate performance summary."""
        trades_df = pd.DataFrame(self.trade_log)
        trades_df.to_csv(r'./Results/pivotmckoutput.csv', index = None, header=True)
        if trades_df.empty:
            print("No trades executed.")
            return

        print("\nTrade Summary:")

        total_trades = len(trades_df)
        completed_df = trades_df[trades_df['tradeState'] == 'completed']
        completed_trades = len(trades_df.loc[trades_df["tradeState"]=="completed"])
        open_trades = len(trades_df.loc[trades_df["tradeState"]=="active"])
        winning_trades = len(completed_df.loc[completed_df["netPnl"] > 0])
        win_rate = winning_trades / completed_trades * 100
        gross_pnl = completed_df["pnl"].sum()
        total_brokerage = completed_df["brokerage"].sum()
        total_pnl = completed_df["netPnl"].sum()
        total_pnl_percent = completed_df["netPnl%"].sum()

        print(f"\nPerformance Metrics:")
        print(f"Total Trades: {total_trades}")
        print(f"Total Completed Trades: {completed_trades}")
        print(f"Total Open Trades: {open_trades}")
        print(f"Total Winning Trades: {winning_trades}")
        print(f"Win Rate: {win_rate:.0f}%")
        print(f"Total Gross Pnl: {gross_pnl:.2f}")
        print(f"Total Brokerage Paid : {total_brokerage:.2f}")
        print(f"Total Net Pnl: {total_pnl:.2f}")
        print(f"Starting Portfolio Balance %: {starting_portfolio:.2f}")
        print(f"Ending Portfolio Value: {self.portfolio_value:.2f}")

        self.trades_df = trades_df  # Store results for analysis


if __name__ == "__main__":

    #### Initial setup - Broker Connection ####
    pd.set_option("display.max_rows", None, "display.max_columns", None)

    #### Instrument Selection ####
    stocks = ["INFY", "HDFCBANK", "RELIANCE", "TCS", "BHARTIARTL", "ICICIBANK", "SBIN", "HINDUNILVR", "ITC",
              "BAJFINANCE"]

    #### Backtesting Period ####
    start_date = dt.date(2024, 1, 1)  # Modify as needed
    end_date = dt.date(2024, 3, 31)  # Modify as needed

    #### Backtest Starts ####
    starting_portfolio = 100000
    backtester = ZeroLossStrategyBacktest(
        stocks=stocks,
        start_date=start_date,
        end_date=end_date,
        use_stoploss=True,    # Change to False to test without stop loss
        starting_portfolio_value=starting_portfolio
    )
    backtester.backtest()

Backtesting Results

Using Python, I backtested this strategy on historical intraday data for the top 10 market cap stocks. The key findings were:

Strengths and Weaknesses

Strengths:

✔ Simple and easy-to-follow rules.
✔ No complicated indicators—just price action.
✔ Works well in a trending market.
✔ Suitable for traders with a long-term holding mindset.

Weaknesses:

❌ No defined stop-loss for long trades, which can be risky.
❌ Short trades require an existing profitable holding, limiting opportunities.
❌ Brokerage and slippages can eat into small profit margins.

Final Thoughts

Mahesh Chander Kaushik’s Zero Loss Intraday Strategy is a simple yet intriguing approach to trading, focusing on price levels rather than complex indicators. While it performs well in a steady market, traders should be cautious about its lack of a strict stop-loss mechanism and potential exposure to market downturns.

Would I personally use this strategy? With modifications! Adding a dynamic stop-loss and filtering trades based on volatility could improve overall performance.

Let me know your thoughts in the comments below, and don’t forget to check out my YouTube video where I explain the Python backtesting code and share detailed results!


Support this community : FabTrader.in is a one-person initiative dedicated to helping individuals on their F.I.R.E. journey. Running and maintaining this community takes time, effort, and resources. If you’ve found value in the content, consider making a donation to support this mission.

Donate

Disclaimer: The information provided in this article is for educational and informational purposes only and should not be construed as financial, investment, or legal advice. The content is based on publicly available information and personal opinions and may not be suitable for all investors. Investing involves risks, including the loss of principal. Always conduct your own research and consult a qualified financial advisor before making any investment decisions. The author and website assume no liability for any financial losses or decisions made based on the information presented.

FabTrader

Vivek is an algorithmic trader, Python programmer, and a passionate advocate of the F.I.R.E. (Financial Independence, Retire Early) movement. He achieved his financial independence at the age of 45 and is dedicated to helping others embark on their own journeys toward financial freedom.

Home
Store
Stories
Algo Trading Platform Using Python Course
About Me

©2024 Fabtrader.in - An unit of Rough Sketch Company. All Rights Reserved

Terms & Conditions
Privacy Policy