Monday, October 20, 2025

Automating Trading Using Python and Understanding Market Direction with Put-Call Ratio Automating Trading Using Python and Understanding Market Direction with Put-Call Ratio

🚀 Automating Trading Using Python and Understanding Market Direction with Put-Call Ratio

In today’s fast-moving trading environment, every second counts. Successful traders are increasingly relying on automation to gain an edge — not just to execute trades faster, but also to process complex data in real time. In this blog, I will share how Python can be used for automating trades and how the Put-Call Ratio (PCR) can be leveraged to predict market direction.

Automation in trading is no longer just for institutions; with Python and open APIs, individual traders can also build efficient, data-driven trading systems without spending heavily on commercial tools or subscriptions.


Introducing My Last Blog on Put-Call Parity

In my last blog, I explained in detail about Open Interest (OI). If you have not read it, please read it at my blog:
👉 https://manishbansal3003.blogspot.com/2024/07/amazing-insights-how-open-interest-can.html.

I will not go into detail again here, but just to recap — OI is a powerful tool to predict market direction. It is not based on sentiment, but on actual positions that retail and institutional traders currently hold. In my previous article, I explained what open interest is, how changes in open interest occur, and how to analyze those changes.

All these are great from a textbook point of view, but when it comes to trading, theory must translate into practice. Unless we can apply our understanding effectively, all these technical terms make no real sense.


How to Use It Practically to Predict Market Movement

Open Interest represents all open contracts in futures and options. We can use options data to understand the market’s directional expectation. To do this effectively, we must understand the option chain.

An option chain displays all the option contracts for a given underlying, starting from the at-the-money (ATM) option, followed by calls and puts above and below that strike.

In a normal market scenario, contracts at or near the money are the most active, while maximum open interest is often seen in deep out-of-the-money (OTM) contracts. Therefore, to use open interest data meaningfully, we need to leverage both the option chain and changes in OI happening across strikes.

Let’s try to understand this with an example:
Suppose Nifty (NSE Index) is trading at 25,000. We will take 20 strike prices above and below to do our analysis — that is, all calls and puts from 24,000 to 26,000.

Let’s assume total open interest for calls (24,000–26,000) is 60,00,000, and for puts it is 80,00,000. After 15 minutes, the data changes to 70,00,000 for calls and 81,00,000 for puts.

So, the change in open interest for calls = 10,00,000, and for puts = 1,00,000. The ratio is 0.1, which means calls have increased 10 times faster than puts.

Usually, this reflects net buying activity from retailers (who are typically net buyers of options). Hence, it’s safer to assume that the market might go down, as large positions are being taken on calls rather than puts.

I will not take credit for this strategy — this concept has been explained by many experienced analysts on various platforms.

My purpose here is to help readers understand how they can apply this strategy without subscribing to expensive platforms.
I am not here to propose any trading strategy for profit-making — my sole purpose is to demonstrate the application of Python for trade automation. (Disclaimer)

However, while this analysis is easy to explain, executing it in real-time is a challenge. Most platforms show OI data but do not provide real-time analysis of OI changes in the option chain.


Using Python on Real-Time Prices to Calculate Change in Open Interest

Let’s now dive into how Python can be used to automate this analysis step by step.

We will use Jupyter Notebook to write this code.

Step 1: Connect to the Broker’s API

First, we need to connect to the broker’s API to get real-time quotes. Most brokers today offer free APIs and documentation, which makes this easy.

Step 2: Get the ATM Strike

Below is a function to get the ATM strike whenever called. This code might vary slightly depending on your broker’s API documentation, but it’s easy to edit. In case of any issue, feel free to contact me via email.

def get_ATM():
    ATM_Strike = round(int(float(client.quotes(instrument_tokens = [{'instrument_token': 53001, 'exchange_segment': 'nse_fo'}], quote_type = "ltp")[0]['ltp'])))
    ATM_Strike = int(round(ATM_Strike/50)*50)
    return ATM_Strike

Step 3: Build the Option Chain

Once we have the ATM strike, we need to get symbols for all the strikes to build the option chain.

# Get list of CE/PE symbols for ±10 strikes around ATM
def get_option_symbols(df_fo, strike_range=20):
    atm = get_ATM()
    prefix = get_next_tuesday_symbol_prefix()

    symbols = []
    for i in range(-strike_range, strike_range + 1):
        strike = atm + (i * 50)
        ce_key = f"{prefix}{strike}.00CE"
        pe_key = f"{prefix}{strike}.00PE"

        try:
            ce_symbol = df_fo[df_fo['pScripRefKey'] == ce_key]['pSymbol'].iloc[0]
            pe_symbol = df_fo[df_fo['pScripRefKey'] == pe_key]['pSymbol'].iloc[0]
            symbols.append({"strike": strike, "CE": ce_symbol, "PE": pe_symbol})
        except IndexError:
            continue

    return symbols
Screenshot

Step 4: Fetch and Resample Real-Time Data

In the next step, we fetch real-time quotes for all option chain contracts and store them in a dataframe.
Quotes usually come in JSON format, so they need to be converted first. I am not going into that detail here, but I can help anyone who wants to build this strategy and customize it to run seamlessly.

Once the quotes are in a dataframe, we can resample them to 5-minute or 15-minute data for analysis.

def dfResample15min(df):
    if not (df.index.name == 'timestamp' and pd.api.types.is_datetime64_any_dtype(df.index)):
        df['timestamp'] = pd.to_datetime(df['timestamp'])
        df.set_index('timestamp', inplace=True)
        df.sort_index(inplace=True)

    df["strike"] = df["strike"].fillna(0)

    results = []
    resample_rule = '15min'

    for (sym, strike, opt_type), group in df.groupby(["symbol", "strike", "option_type"]):
        ohlc = group['ltp'].resample(resample_rule, label='right', closed='right').ohlc()
        oi_last = group['open_int'].resample(resample_rule, label='right', closed='right').last()
        oi_open = group['open_int'].resample(resample_rule, label='right', closed='right').first()

        oi_change = oi_last.diff()
        oi_change.iloc[0] = oi_last.iloc[0] - oi_open.iloc[0]

        vol_last = group['last_volume'].resample(resample_rule, label='right', closed='right').last()
        vol_open = group['last_volume'].resample(resample_rule, label='right', closed='right').first()

        vol_change = vol_last.diff()
        vol_change.iloc[0] = vol_last.iloc[0] - vol_open.iloc[0]

        res = pd.concat([ohlc, oi_last.rename('open_int'), vol_last.rename('volume'), oi_change.rename('oi_change'), vol_change.rename('volume_change')], axis=1)

        res["symbol"] = sym
        res["strike"] = strike
        res["option_type"] = opt_type
        results.append(res.reset_index())

    return pd.concat(results, ignore_index=True)
Screenshot

Step 5: Build Total Cumulative OI Change and PCR

We can now calculate cumulative OI change for calls and puts and derive the Put-Call Ratio.

def build_total_oi_change_cumulative(df_15):
    df_15 = df_15.sort_values("timestamp")

    call_df = (
        df_15[df_15["option_type"] == "CE"]
        .groupby("timestamp")["oi_change"]
        .sum()
        .cumsum()
        .rename("call_oi_cum")
    )

    put_df = (
        df_15[df_15["option_type"] == "PE"]
        .groupby("timestamp")["oi_change"]
        .sum()
        .cumsum()
        .rename("put_oi_cum")
    )

    total_df = pd.concat([call_df, put_df], axis=1).fillna(0)
    total_df["PCR"] = abs(total_df["put_oi_cum"]) / abs(total_df["call_oi_cum"]).replace(0, np.nan)
    total_df["PCR"] = total_df["PCR"].replace([np.inf, -np.inf, np.nan], 0)

    return total_df.reset_index()
Screenshot

Step 6: Building an Automated Trading System

By integrating this logic with trade-entry and exit rules, you can create a fully automated trading system.
Though I have not shared all the broker-specific code here (since it varies), I have covered the core logic that forms the foundation of a PCR-based strategy.

In the build_total_oi_change_cumulative(df_15) function, notice how the code sorts timestamps, groups data by option type, calculates cumulative OI change, and computes PCR as the ratio of cumulative put OI to cumulative call OI.

This is just one simple strategy to demonstrate how powerful Python is as a tool for automating trading.
Similarly, we can use real-time data to calculate Option Greeks, manage delta-neutral portfolios, or design multi-indicator strategies.

In fact, I have already built one strategy where I take a position and dynamically manage it to stay delta-neutral using multiple indicators — but I will cover that in my next blog, where I’ll explain how to use Option Greeks in Python.


🔍 Conclusion: Why You Should Start Automating Trades with Python

Python is a game-changer for modern traders. It bridges the gap between financial theory and real-world execution. With a few lines of code, you can collect, analyze, and act on live market data in real time — all without relying on costly subscriptions or platforms.

By automating your strategy, you reduce human error, gain consistency, and ensure disciplined execution. Whether it’s through the Put-Call Ratio, Option Greeks, or custom technical indicators, Python empowers you to take full control of your trading process.

If you’ve ever thought that trading automation is only for tech experts — think again. With Python, even non-programmers can start small, automate parts of their strategy, and grow steadily.


Take Control of Your Finances Today!

If you want to plan your finances effectively and take actionable steps that lead to real, measurable results, I can help. From budgeting and accounting to evaluating the feasibility of your financial plans, we’ll work together to set clear goals and achieve them.

📧 Email: bansalmanish30003@gmail.com
📞 Call: 7003426212

Let’s turn your financial goals into reality—reach out and get started!

About the Author:
Manish is a Chartered Accountant by profession and a passionate writer who loves exploring human behavior, finance, and the intersection of professional life with personal growth. Through his blogs, he shares practical insights drawn from real-world experience to inspire working professionals toward financial and personal independence.
© 2025 Manish Bansal | All Rights Reserved

⚠️ Disclaimer

I am not providing any trading advice or tips in this blog.
My sole purpose is to demonstrate how Python can be leveraged as a powerful tool for trade automation and to inspire traders to explore automation responsibly.

No comments:

Post a Comment

10 Most-Used Libraries to Automate Trading and Make Money in the Share Market ...