# 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.

***

***


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.openalgo.in/trading-platform/python/intraday-rolling-straddles.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
