> For the complete documentation index, see [llms.txt](https://docs.openalgo.in/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.openalgo.in/trading-platform/python/intraday-rolling-straddles.md).

# Intraday Rolling Straddles

### **Overview**

This sample strategy implements an **intraday rolling short straddle** for NIFTY index options using OpenAlgo Python APIs. The bot sells an at-the-money (ATM) NIFTY straddle at a configurable time, then automatically rolls (closes and reopens a new straddle) whenever the NIFTY spot moves ±0.4% from the last entry reference, up to a user-defined daily limit. All open positions are force-closed (squared off) at a specified time before market close.

***

### **Key Features**

* **Instrument:** NIFTY Index Options (customizable)
* **Fixed Expiry:** All option orders use the expiry you set (e.g., `19JUN25`)
* **Entry:** Places the first ATM straddle at a configurable time (e.g., 10:00 a.m.)
* **Rolling Trigger:** Monitors the NIFTY spot price; rolls to a new ATM straddle on every 0.4% move from the last reference point
* **Order Limit:** Limits the number of rolling straddles per day (default: 3, can be changed)
* **Exit:** Squares off all open legs at a configurable EOD time (e.g., 3:15 p.m.)
* **All times in IST** (Asia/Kolkata timezone)
* **No database or persistent logs** — actions are printed to the console for full transparency
* **Parameter-based configuration:** Change any key value by simply editing the variable at the top of the script

### **Python Strategy**

```python
import time as systime
from datetime import datetime, time as dtime
from apscheduler.schedulers.background import BackgroundScheduler
from openalgo import api
import pytz

print("🔁 OpenAlgo Python Bot is running.")

# === USER PARAMETERS ===

STRADDLE_ENTRY_HOUR = 10      # 10 for 10:00 AM
STRADDLE_ENTRY_MINUTE = 0     # 0 for 10:00 AM

SQUAREOFF_HOUR = 15           # 15 for 3:15 PM
SQUAREOFF_MINUTE = 15         # 15 for 3:15 PM

MAX_STRADDLES_PER_DAY = 3     # Daily limit on rolling straddles
ROLLING_THRESHOLD_PCT = 0.4   # Threshold for rolling (in percent, e.g. 0.4 means 0.4%)

LOT_SIZE = 75
STRATEGY = "rolling_straddle"
SYMBOL = "NIFTY"
EXPIRY = "19JUN25"
EXCHANGE = "NSE_INDEX"
OPTION_EXCHANGE = "NFO"
STRIKE_INTERVAL = 50

API_KEY = "YOU-OPENALGO-APIKEY"
API_HOST = "http://127.0.0.1:5000"

client = api(api_key=API_KEY, host=API_HOST)

def get_atm_strike(spot):
    return int(round(spot / STRIKE_INTERVAL) * STRIKE_INTERVAL)

def get_spot():
    quote = client.quotes(symbol=SYMBOL, exchange=EXCHANGE)
    print("Quote:", quote)
    data = quote['data']
    if isinstance(data, list):
        data = data[0]
    return data['ltp']

def get_option_symbol(base, expiry, strike, opttype):
    return f"{base}{expiry}{strike}{opttype}"

# --- State ---
last_reference_spot = None
current_leg_symbols = []
straddle_entry_count = 0

def reset_daily_counter():
    global straddle_entry_count
    straddle_entry_count = 0
    print(f"Daily straddle entry counter reset to zero at {datetime.now()}")

def place_straddle():
    global last_reference_spot, current_leg_symbols, straddle_entry_count
    if straddle_entry_count >= MAX_STRADDLES_PER_DAY:
        print(f"Straddle entry limit ({MAX_STRADDLES_PER_DAY}) reached for today.")
        return
    spot = get_spot()
    atm_strike = get_atm_strike(spot)
    ce = get_option_symbol(SYMBOL, EXPIRY, atm_strike, "CE")
    pe = get_option_symbol(SYMBOL, EXPIRY, atm_strike, "PE")
    for sym in [ce, pe]:
        order = client.placeorder(
            strategy=STRATEGY, symbol=sym, action="SELL",
            exchange=OPTION_EXCHANGE, price_type="MARKET",
            product="MIS", quantity=LOT_SIZE
        )
        print(f"Order placed for {sym}: {order}")
    last_reference_spot = spot
    current_leg_symbols = [ce, pe]
    straddle_entry_count += 1
    print(f"Straddle Entry Count updated: {straddle_entry_count}")

def close_straddle():
    for sym in current_leg_symbols:
        order = client.placeorder(
            strategy=STRATEGY, symbol=sym, action="BUY",
            exchange=OPTION_EXCHANGE, price_type="MARKET",
            product="MIS", quantity=LOT_SIZE
        )
        print(f"Order EXIT for {sym}: {order}")

def rolling_monitor():
    global last_reference_spot
    spot = get_spot()
    print(f"Spot: {spot}")
    print(f"Last Reference Spot: {last_reference_spot}")
    threshold = last_reference_spot * (ROLLING_THRESHOLD_PCT / 100.0)
    if abs(spot - last_reference_spot) >= threshold:
        print(f"Rolling: Spot moved {spot} from ref {last_reference_spot} (Threshold: {threshold})")
        close_straddle()
        place_straddle()

def eod_exit():
    print("EOD exit triggered.")
    close_straddle()

# === Scheduler ===
scheduler = BackgroundScheduler(timezone="Asia/Kolkata")
scheduler.add_job(reset_daily_counter, 'cron', day_of_week='mon-fri', hour=STRADDLE_ENTRY_HOUR, minute=STRADDLE_ENTRY_MINUTE)
scheduler.add_job(place_straddle, 'cron', day_of_week='mon-fri', hour=STRADDLE_ENTRY_HOUR, minute=STRADDLE_ENTRY_MINUTE)
scheduler.add_job(eod_exit, 'cron', day_of_week='mon-fri', hour=SQUAREOFF_HOUR, minute=SQUAREOFF_MINUTE)
scheduler.start()

try:
    while True:
        now = datetime.now(pytz.timezone("Asia/Kolkata")).time()
        entry_start = dtime(STRADDLE_ENTRY_HOUR, STRADDLE_ENTRY_MINUTE)
        squareoff_time = dtime(SQUAREOFF_HOUR, SQUAREOFF_MINUTE)
        # Rolling monitor runs during straddle session only
        if entry_start < now < squareoff_time and last_reference_spot:
            rolling_monitor()
        systime.sleep(5)
except (KeyboardInterrupt, SystemExit):
    scheduler.shutdown()

```

***

### **Parameters (Edit at Top of Script)**

| Variable                | Purpose                                           | Example     |
| ----------------------- | ------------------------------------------------- | ----------- |
| `STRADDLE_ENTRY_HOUR`   | Hour to enter first straddle (24h format)         | `10`        |
| `STRADDLE_ENTRY_MINUTE` | Minute to enter first straddle                    | `0`         |
| `SQUAREOFF_HOUR`        | Hour to force square-off all legs                 | `15`        |
| `SQUAREOFF_MINUTE`      | Minute to force square-off all legs               | `15`        |
| `MAX_STRADDLES_PER_DAY` | Max straddles allowed per day                     | `3`         |
| `EXPIRY`                | Expiry date for all option legs (OpenAlgo format) | `"19JUN25"` |
| `LOT_SIZE`              | Number of options per leg (NIFTY = 75 as of 2025) | `75`        |

***

### **Order Format**

All orders use the OpenAlgo symbol format:

* **Call Example:** `NIFTY19JUN2522350CE`
* **Put Example:** `NIFTY19JUN2522350PE`

Orders are placed as:

* **Type:** `MARKET`
* **Action:** `SELL` (entry), `BUY` (exit)
* **Product:** `MIS`
* **Exchange:** `NFO`

***

### **How the Strategy Works**

1. **Start & First Entry:**\
   At your configured entry time (e.g., 10:00 a.m.), the bot sells 1 lot of ATM NIFTY CE and PE for the expiry you set.
2. **Rolling Logic:**\
   Every 5 seconds, the bot checks the latest NIFTY spot. If the spot moves up or down by at least 0.4% from the last entry reference, the bot:
   * Closes both legs of the current straddle
   * Sells a new ATM CE and PE (same expiry, current ATM)
3. **Daily Straddle Limit:**\
   The bot never enters more straddles than the daily limit you set. (Default: 3 per day)
4. **End-of-Day Squareoff:**\
   At your configured squareoff time (e.g., 3:15 p.m.), any open straddle is closed, and no further trades are placed for the day.
5. **Console Logging:**\
   All quotes, trades, entries, exits, and reference changes are clearly printed in real time.

***

### **Usage**

* Edit the parameters at the top of the script as needed (no need for .env or environment variables).
* Run the script. Ensure your OpenAlgo API is running and accessible.
* All actions and errors will be displayed in your terminal or console.

***

### **Limitations and Notes**

* This sample does **not** use persistent order logging or database.
* No explicit risk management or stop loss (can be added if desired).
* Only supports one instrument/expiry at a time.
* Ensure your OpenAlgo symbol format and expiry match your broker’s contract details.

***

***
