BankNifty Option Buying strategy with Python
BankNIFTY Trading with FYERS API

I delved into the world of trading with Python, specifically exploring the capabilities of the FYERS API. Inspired by the potential for algorithmic trading, I crafted a simple yet insightful price reference strategy tailored for trading BankNIFTY. In this forthcoming blog post, I'm excited to share my discoveries with you. From navigating the intricacies of the FYERS API to mastering order placements and tracking, I'll walk you through each step of the process. However, a crucial disclaimer: while this strategy serves as a valuable learning tool, I urge caution and advise against its use in real-time trading scenarios. Let's embark on this educational journey together, empowering beginners to craft their own trading algorithms with Python.

Step One :

This code snippet automates the authentication process for accessing the FYERS API using Python. It initializes a web browser, navigates to the authorization URL, waits for the authorization code to be obtained, saves it to a text file, and then exchanges it for an access token. Finally, it initializes a client for interacting with the FYERS API. However, it could benefit from improved error handling and additional comments for clarity.

Bash Script Code Showcase

from fyers_apiv3 import fyersModel
import webbrowser
import requests
from selenium import webdriver
import time
import os
driver = webdriver.Firefox()
redirect_uri= "https://127.0.0.1:5000/login"
client_id = "VXXXXXXXX-100"
secret_key = “XXXXXXXX”
grant_type = "authorization_code"
response_type = "code"
state = "sample"
appSession = fyersModel.SessionModel(client_id = client_id, redirect_uri = redirect_uri,response_type=response_type,state=state,secret_key=secret_key,grant_type=grant_type)
generateTokenUrl = appSession.generate_authcode()
url_to_open = generateTokenUrl
driver.get(url_to_open)
current_url = driver.current_url
while 'code=200' not in current_url:
    print('Waiting to the AuthCode')
    time.sleep(5)
    current_url = driver.current_url
driver.quit()
file_path = "Fyerstoken.txt"
if os.path.exists(file_path):
   os.remove(file_path)
else:
   print("File not found.")
file = open('Fyerstoken.txt','a')
file.write(str(current_url.split('=')[3]))
file.close()
appSession.set_token(current_url.split('&')[2].split('=')[1])
response = appSession.generate_token()
try:
    access_token = response["access_token"]
except Exception as e:
    print(e,response)
fyers = fyersModel.FyersModel(token=access_token,is_async=False,client_id=client_id,log_path="")
        

Step Two :

In the next phase of refining my trading strategy utilizing the FYERS API, I crafted a series of custom functions aimed at facilitating seamless execution and management of trades. Here's a snapshot of the functions I've developed:

  1. close_all_positions: This function enables the systematic closure of all existing positions, providing a streamlined approach to managing portfolio exposure.
  2. close_position: Designed to close a specific position, this function offers targeted control over individual trades within the portfolio.
  3. get_openposition_id: With this function, traders can retrieve the unique identifier for each open position, facilitating precise tracking and management.
  4. cancel_all_open_orders: Offering a swift solution to cancel all pending orders, this function ensures agility in adjusting trade plans as market conditions evolve.
  5. place_SL_order, place_limit_order, place_market_order: These functions empower traders with versatile order placement options, including stop-loss, limit, and market orders, catering to diverse trading strategies.
  6. check_price_level: This function compares the current price of bank nifty index with the reference price and returns the value to buy/sell or wait.
  7. get_ltp: By providing real-time access to price data, these functions enable traders to monitor market movements and make informed decisions.
  8. check_total_PNL: This function calculates the total profit and closes the positions if the max profit or loss is achieved.
  9. current_BN_ATM_CE, current_BN_ATM_PE: Tailored for options trading, these functions identify the current at-the-money call and put options for Bank NIFTY, aiding in strategy formulation.
  10. get_openposition_side: This function retrieves if the open position is a call buy or a put buy.

These functions collectively serve to enhance the flexibility, efficiency, and effectiveness of the trading strategy, empowering traders to execute with precision and confidence.

Bash Script Code Showcase


import requests
def close_all_positions(client_id,access_token):
    url = "https://api-t1.fyers.in/api/v3/positions"
    Token = client_id + ':' + access_token
    headers = {
        "Authorization": Token,
        # Replace YOUR_ACCESS_TOKEN with your actual access token
        "Content-Type": "application/json"
    }
    data = {"exit_all": 1}
    response = requests.delete(url, headers=headers, json=data)
    print(response.text)

def close_position(client_id,access_token,id):
    url = "https://api-t1.fyers.in/api/v3/positions"
    Token = client_id + ':' + access_token
    headers = {
        "Authorization": Token,
        # Replace YOUR_ACCESS_TOKEN with your actual access token
        "Content-Type": "application/json"
    }
    if id:
        data = {
            "id": id
        }
    else:
        data = {
            "id": 'NoSymbolData'
        }
    response = requests.delete(url, headers=headers, json=data)
    print(response.text)

def get_openposition_id(allPositions):
    if ([obj for obj in allPositions if obj["netQty"] > 1]):
        loop = [obj for obj in allPositions if obj["netQty"] > 1]
        data4 = []
        for singlePosition in loop:
            data4.append(singlePosition.get('id'))
        return data4
    else:
        print('There is no open position')

#print( get_openposition_id(allPositions))


def cancel_all_open_orders(client_id,access_token):
    ord1 = fyers.orderbook()['orderBook']
    for ord2 in ([obj for obj in ord1 if obj["status"] == 6]):
        url = "https://api-t1.fyers.in/api/v3/orders/sync"
        headers = {
            "Authorization": client_id + ':' + access_token,
            "Content-Type": "application/json"
        }
        data = {
            "id": ord2['id']
        }
        print(ord2['id'])
        response = requests.delete(url, headers=headers, json=data)
        print(response.text)

def place_SL_order(client_id,access_token,symbol,side,quantity,limitprice,stoploss):
    import requests
    url = "https://api-t1.fyers.in/api/v3/orders/sync"
    headers = {
        "Authorization": client_id + ':' + access_token,
        "Content-Type": "application/json"
    }
    data = {
            "symbol": symbol,
            "qty": quantity,
            "type": 4,
            "side": side,
            "productType": "INTRADAY",
            "limitPrice": limitprice,
            "stopPrice": stoploss,
            "validity": "DAY",
            "disclosedQty": 0,
            "offlineOrder": False,
            "stopLoss": 0,
            "takeProfit": 0,
            "orderTag": "tag1"
        }

    response = requests.post(url, headers=headers, json=data)
    return (response.text)

def place_limit_order(client_id,access_token,symbol,side,quantity,limitprice):
    import requests
    url = "https://api-t1.fyers.in/api/v3/orders/sync"
    headers = {
        "Authorization": client_id + ':' + access_token,
        "Content-Type": "application/json"
    }
    data = {
            "symbol": symbol,
            "qty": quantity,
            "type": 1,
            "side": side,
            "productType": "INTRADAY",
            "limitPrice": limitprice,
            "stopPrice": 0,
            "validity": "DAY",
            "disclosedQty": 0,
            "offlineOrder": False,
            "stopLoss": 0,
            "takeProfit": 0,
            "orderTag": "tag1"
        }

    response = requests.post(url, headers=headers, json=data)
    return (response.text)


def place_market_order(client_id,access_token,symbol,side,quantity):
    url = "https://api-t1.fyers.in/api/v3/orders/sync"
    headers = {
        "Authorization": client_id + ':' + access_token,
        "Content-Type": "application/json"
    }
    data = {
            "symbol": symbol,
            "qty": quantity,
            "type": 2,
            "side": side,
            "productType": "INTRADAY",
            "limitPrice": 0,
            "stopPrice": 0,
            "validity": "DAY",
            "disclosedQty": 0,
            "offlineOrder": False,
            "stopLoss": 0,
            "takeProfit": 0,
            "orderTag": "tag1"
        }

    response = requests.post(url, headers=headers, json=data)
    return (response.text)

import requests
def check_price_level(client_id,access_token,symbol,referenceLevel):
    url = 'https://api-t1.fyers.in/data/quotes?symbols=' + symbol
    headers = {
        'Authorization': client_id + ':' + access_token
    }
    response = requests.get(url, headers=headers)
    if ((response.json())['d'][0]['v']['lp']) > (referenceLevel+10):
        return 'buy'
    elif ((response.json())['d'][0]['v']['lp']) < (referenceLevel-10):
        return 'sell'
    else:
        return 'wait'

def get_ltp(client_id,access_token,symbol):
    url = 'https://api-t1.fyers.in/data/quotes?symbols=' + symbol
    headers = {
        'Authorization': client_id + ':' + access_token
    }
    response = requests.get(url, headers=headers)
    return ((response.json())['d'][0]['v']['lp'])


def check_total_PNL():
    if int(fyers.positions()['overall']['pl_total']) > 5000:
        close_all_positions(client_id, access_token)

    elif int(fyers.positions()['overall']['pl_total']) < -2200:
        close_all_positions(client_id, access_token)

    else:
        print("No profit and loss booking happened")



def current_BN_ATM_CE(strikeDistance = 0):
    brokerSymbol = 'NSE:BANKNIFTY24430'
    TikerPrice = int(get_ltp(client_id,access_token,'NSE:NIFTYBANK-INDEX'))
    StraikPrice = str(str(int((TikerPrice + strikeDistance) / 100) ) + '00')
    CE_PE = 'CE'
    return brokerSymbol + StraikPrice + CE_PE

def current_BN_ATM_PE(strikeDistance = 0):
    brokerSymbol = 'NSE:BANKNIFTY24430'
    TikerPrice = int(get_ltp(client_id,access_token,'NSE:NIFTYBANK-INDEX'))
    StraikPrice = str(str(int((TikerPrice - strikeDistance) / 100) ) + '00')
    CE_PE = 'PE'
    return brokerSymbol + StraikPrice + CE_PE


def get_openposition_side(allPositions):
    if ([obj for obj in allPositions if obj["netQty"] > 0]):
        loop = [obj for obj in allPositions if obj["netQty"] > 0]
        for singlePosition in loop:
            current_buy_sell_status = singlePosition.get('side')
            if "CE" in singlePosition.get('symbol'):
                length = len(([obj for obj in allPositions if obj["netQty"] > 0])[0]['symbol'])
                ce_or_pe = ([obj for obj in allPositions if obj["netQty"] > 0])[0]['symbol'][length-2:length+1]
                return ce_or_pe
            elif "PE" in singlePosition.get('symbol'):
                length = len(([obj for obj in allPositions if obj["netQty"] > 0])[0]['symbol'])
                ce_or_pe = ([obj for obj in allPositions if obj["netQty"] > 0])[0]['symbol'][length-2:length+1]
                return ce_or_pe
            else:
                return "noPosition"
    else:
        return "noPosition"

       

Step Three:

In the third stage of refining our trading strategy, let's delve into the core methodology we've devised for navigating the Bank NIFTY market. This is a plain option buying strategy according to the price change. Here's a breakdown of the key steps involved:

  1. Reference Price Setup: To kickstart our strategy, we first fetch the current price of the Bank NIFTY index and designate it as our reference price.
  2. ATM Calls and Puts: Next, we retrieve the current at-the-money (ATM) call and put options for Bank NIFTY, laying the groundwork for our trade decisions.
  3. Continuous Price Tracking: We initiate a continuous monitoring process, checking the Bank NIFTY price at 30-second intervals to stay abreast of market movements.
  4. Buy Order Placement: Should the Bank NIFTY price surge above our reference price by 10 points, we swiftly execute a buy order for the ATM call option. If any prior orders exist, we close them before initiating the new trade.
  5. Sell Order Placement: Conversely, if the Bank NIFTY price dips below our reference price by 10 points, we promptly place a sell order for the ATM put option, again ensuring closure of any existing orders beforehand.
  6. Wait-and-Watch Strategy: While the Bank NIFTY price remains within the range of +/- 10 points from our reference price, we adopt a patient stance, awaiting a decisive movement in either direction.
  7. Profit and Loss Monitoring: At every 30-second interval, we diligently monitor our trade positions. If our profit reaches 5000, we opt to exit all active orders. Similarly, to mitigate losses, we've set a maximum loss threshold of 2000.

This comprehensive strategy leverages real-time market data and precise order execution to capitalize on favorable price movements while mitigating potential risks.

Bash Script Code Showcase

from fyers_apiv3.FyersWebsocket import data_ws
import time
import pandas as pd
from fyers_apiv3 import fyersModel
import os
fyers = fyersModel.FyersModel(token=’token’,is_async=False,client_id='VXXXXXXXI-100',log_path="")
ReferencePrice = int(get_ltp(client_id,access_token,'NSE:NIFTYBANK-INDEX'))

def onmessage(message):
    print("Response:", message['ltp'])

    ltp = message['ltp']
    symbol='NSE:NIFTYBANK-INDEX'
    allPositions = fyers.positions()['netPositions']
    current_position_side = get_openposition_side(allPositions)
    buy_sell_status = check_price_level(client_id,access_token,symbol,ReferencePrice)

    if buy_sell_status == 'buy' and current_position_side != 'CE':
        if ([obj for obj in allPositions if obj["netQty"] > 0]):
            close_all_positions(client_id, access_token)
        else:
            print('')
        buy_symbol = current_BN_ATM_CE()
        place_market_order(client_id,access_token,buy_symbol,1,15)

    elif buy_sell_status == 'sell' and current_position_side != 'PE':
        if ([obj for obj in allPositions if obj["netQty"] > 0]):
            close_all_positions(client_id, access_token)
        else:
            print('')
        sell_symbol = current_BN_ATM_PE()
        place_market_order(client_id,access_token,sell_symbol,1,15)

    else:
        print("Waiting for correct price.")
    check_total_PNL()
    time.sleep(30)


def onerror(message):
    print("Error:", message)


def onclose(message):
    print("Connection closed:", message)


def onopen():
    data_type = "SymbolUpdate"
    symbols = ['NSE:NIFTYBANK-INDEX']
    fyers1.subscribe(symbols=symbols, data_type=data_type)
    fyers1.keep_running()

access_token_data = ‘XXXXXXX-100:' + access_token
# Create a FyersDataSocket instance with the provided parameters
fyers1 = data_ws.FyersDataSocket(
    access_token=access_token_data,
    log_path="",
    litemode=True,
    write_to_file=False,
    reconnect=True,
    on_connect=onopen,
    on_close=onclose,
    on_error=onerror,
    on_message=onmessage
)
# Establish a connection to the Fyers WebSocket
fyers1.connect()
      

Reference :
https://myapi.fyers.in/


Siddartha Kumar Das
About Siddartha Kumar Das

Tech Enthusiast

Topics