Spaces:
Running
Running
| """ | |
| Dump raw 5m OHLC that the backtest actually read for a given trade — | |
| both the underlying stock and the option — so you can visually compare | |
| against TradingView / Kite chart and spot data glitches. | |
| Usage: | |
| python debug_trade.py --symbol ANGELONE --option ANGELONE26APR315CE --date 2026-04-17 --around 12:30 | |
| Prints a window of bars around the time of interest, plus the exact | |
| indication / confirmation / trigger bars so you can see what prices | |
| strategy-1 saw. | |
| """ | |
| from __future__ import annotations | |
| import argparse | |
| from datetime import datetime, timedelta, time | |
| from pathlib import Path | |
| import pandas as pd | |
| from history_utils import get_stock_5m, get_option_5m | |
| from indicators_v2 import add_strategy_indicators_v2 | |
| def _fmt(df: pd.DataFrame, extra_cols=None) -> str: | |
| base = ["timestamp", "open", "high", "low", "close", "volume"] | |
| cols = [c for c in base if c in df.columns] | |
| if extra_cols: | |
| cols += [c for c in extra_cols if c in df.columns and c not in cols] | |
| return df[cols].to_string(index=False) | |
| def main(): | |
| ap = argparse.ArgumentParser() | |
| ap.add_argument("--symbol", required=True, help="Underlying stock symbol (e.g., ANGELONE)") | |
| ap.add_argument("--option", required=True, help="Option tradingsymbol (e.g., ANGELONE26APR315CE)") | |
| ap.add_argument("--date", required=True, help="Trade date YYYY-MM-DD") | |
| ap.add_argument("--around", default="12:30", help="Time of interest HH:MM (IST)") | |
| ap.add_argument("--window-min", type=int, default=30, help="Minutes before/after to show (default 30)") | |
| args = ap.parse_args() | |
| day = pd.Timestamp(args.date).date() | |
| around_h, around_m = [int(x) for x in args.around.split(":")] | |
| around_ts = datetime.combine(day, time(around_h, around_m)) | |
| win = timedelta(minutes=args.window_min) | |
| fetch_from = datetime.combine(day - timedelta(days=5), time(9, 15)) | |
| fetch_to = datetime.combine(day, time(15, 30)) | |
| print(f"=== UNDERLYING {args.symbol} on {args.date} ===") | |
| stock = get_stock_5m(args.symbol, fetch_from, fetch_to) | |
| if stock.empty: | |
| print("(no stock data)") | |
| else: | |
| stock = add_strategy_indicators_v2(stock) | |
| stock["timestamp"] = pd.to_datetime(stock["timestamp"]) | |
| day_stock = stock[stock["timestamp"].dt.date == day].copy() | |
| day_stock["body_high"] = day_stock[["open", "close"]].max(axis=1) | |
| day_stock["body_low"] = day_stock[["open", "close"]].min(axis=1) | |
| ts_naive = day_stock["timestamp"].dt.tz_localize(None) if day_stock["timestamp"].dt.tz is not None else day_stock["timestamp"] | |
| mask = (ts_naive >= (around_ts - win)) & (ts_naive <= (around_ts + win)) | |
| view = day_stock[mask] | |
| print(_fmt(view, extra_cols=[ | |
| "body_high", "body_low", | |
| "bb_phase", "ema5", "ema9", "ck_dir", "jghla_dir", | |
| ])) | |
| print(f"\n=== OPTION {args.option} on {args.date} ===") | |
| try: | |
| opt = get_option_5m(args.option, fetch_from, fetch_to) | |
| except Exception as e: | |
| print(f"(error fetching option: {e})") | |
| return | |
| if opt.empty: | |
| print("(no option data - possibly expired beyond retention window)") | |
| return | |
| opt["timestamp"] = pd.to_datetime(opt["timestamp"]) | |
| day_opt = opt[opt["timestamp"].dt.date == day].copy() | |
| day_opt["body_high"] = day_opt[["open", "close"]].max(axis=1) | |
| day_opt["body_low"] = day_opt[["open", "close"]].min(axis=1) | |
| ts_naive = day_opt["timestamp"].dt.tz_localize(None) if day_opt["timestamp"].dt.tz is not None else day_opt["timestamp"] | |
| mask = (ts_naive >= (around_ts - win)) & (ts_naive <= (around_ts + win)) | |
| view = day_opt[mask] | |
| print(_fmt(view, extra_cols=["body_high", "body_low"])) | |
| # Highlight the bars the backtest keyed off | |
| print("\n=== KEY BARS BACKTEST USED ===") | |
| ind_ts = around_ts - timedelta(minutes=5) # confirmation - 1 bar | |
| conf_ts = around_ts # confirmation bar | |
| trig_ts_a = around_ts + timedelta(minutes=5) # first trigger check | |
| trig_ts_b = around_ts + timedelta(minutes=10) # second trigger check | |
| print(f"indication bar : {ind_ts} (strategy-1 stop_loss = body_low of this option candle)") | |
| print(f"confirmation bar : {conf_ts} (trigger level = body_high of this underlying candle)") | |
| print(f"trigger bar(s) : {trig_ts_a} / {trig_ts_b} (entry fires on break; buy_price = body_high of option candle at that bar)") | |
| if __name__ == "__main__": | |
| main() |