اوپننگ رینج بریک تھرو اے ٹی آر ٹریلنگ اسٹاپ نقصان کی حکمت عملی

ATR OR SMC 量化交易 追踪止损 开盘区间突破 风险管理 交易自动化
تخلیق کی تاریخ: 2025-07-31 10:51:36 آخر میں ترمیم کریں: 2025-07-31 10:51:36
کاپی: 0 کلکس کی تعداد: 266
2
پر توجہ دیں
319
پیروکار

اوپننگ رینج بریک تھرو اے ٹی آر ٹریلنگ اسٹاپ نقصان کی حکمت عملی اوپننگ رینج بریک تھرو اے ٹی آر ٹریلنگ اسٹاپ نقصان کی حکمت عملی

حکمت عملی کا جائزہ

اوپننگ رینج بریک آؤٹ اے ٹی آر ٹریکنگ اسٹاپ اسٹریٹجی ایک مقداری تجارتی نظام ہے جو اوپننگ رینج بریک آؤٹ اور سمارٹ منی تصورات کو سمارٹ مارکیٹ تجزیہ کے ساتھ جوڑتا ہے۔ یہ حکمت عملی امریکی اسٹاک مارکیٹ کے کھلنے کے 5 منٹ بعد (9: 30-09: 35 EST) میں قیمت کے علاقے میں توڑنے کے مواقع کو پکڑنے پر مرکوز ہے ، اور متعدد فلٹرنگ شرائط کے ساتھ مل کر ٹریڈنگ سگنل کی معیار کو یقینی بناتا ہے۔ یہ نظام فوری طور پر یا واپسی کی حمایت کرتا ہے۔

حکمت عملی کا اصول

اوپننگ رینج کو توڑنے کے لئے اے ٹی آر ٹریکنگ اسٹاپ اسٹریٹجی کی بنیادی منطق مارکیٹ کے کھلنے کے بعد ابتدائی قیمتوں کے فاصلے کی اہمیت پر مبنی ہے۔ یہ حکمت عملی سب سے پہلے مخصوص وقت کے ونڈو ((09:30-09:35 EST) میں قیمتوں کے اعلی ترین اور کم ترین مقامات کو پکڑتی ہے اور ریکارڈ کرتی ہے ، جس سے “اوپننگ رینج” (Opening Range) تشکیل پاتی ہے۔ اس کے بعد ، سسٹم اس فاصلے پر قیمتوں کی نگرانی کرتا ہے جس میں مندرجہ ذیل کلیدی میکانزم کو جوڑ کر ٹریڈنگ کے معیار کو یقینی بناتا ہے:

  1. کھلے علاقے کی شناخت اور توڑ کی تصدیق: سسٹم مخصوص وقت کے ونڈو کے اندر قیمت کے اعلی ترین اور کم ترین مقامات کو ریکارڈ کرتا ہے ، اور پھر اس کی نگرانی کی جاتی ہے کہ آیا اس میں کوئی خرابی ہوئی ہے۔ خرابی کو دوہری فلٹرنگ میکانزم کے ذریعے تصدیق کرنا ہوگی:

    • شیڈو لائن فی صد فلٹرنگ: اس بات کو یقینی بنائیں کہ شیڈو میں داخل ہونے والی اوپر / نیچے کی لائنیں شیڈو کی ہستی کے مخصوص فیصد سے زیادہ نہ ہوں ، تاکہ جھوٹے ٹوٹنے سے بچا جاسکے۔
    • بریک فاصلہ فلٹرنگ: اس بات کو یقینی بنائیں کہ قیمت کی بریک مناسب ہے ، نہ تو بہت چھوٹی ((چھوٹی چھوٹی بریک سے بچیں) ، اور نہ ہی بہت بڑی ((زیادہ توسیع سے بچیں)) ۔
  2. داخلے کا طریقہ کاراس کے علاوہ ، یہ بھی کہا گیا ہے کہ:

    • فوری اندراج: ایک ہی چارٹ پر براہ راست اندراج جس میں تصدیق شدہ توڑ کی تصدیق کی گئی ہے۔
    • واپسی کی واپسی: قیمت کی واپسی کا انتظار کریں تاکہ اس سے آگے بڑھنے والے اداروں کی مخصوص فیصد پوزیشن پر واپسی کی جائے ، عام طور پر 50٪ واپسی کی پوزیشن پر سیٹ کی جاسکتی ہے۔
  3. سٹاپ نقصان کی ترتیباتسسٹم دو قسم کے سٹاپ نقصان فراہم کرتا ہے:

    • توڑ پھوڑ کا نقصان: توڑ پھوڑ کے انتہائی نقطہ سے باہر نقصان کی روک تھام کو ترتیب دیں۔
    • سمت زون کی روک تھام: قیمتوں میں زیادہ اتار چڑھاؤ کی گنجائش فراہم کرنے کے لئے کھلے زون کی سمت کی سرحد سے باہر اسٹاپ نقصان کی ترتیب دیں۔
  4. رسک مینجمنٹ: سسٹم میں رسک: انعام ملٹی پلیئر کا استعمال کیا گیا ہے جو خود بخود اسٹاپ پوزیشن کا حساب لگاتا ہے ، متحرک رسک مینجمنٹ کو لاگو کرتا ہے۔ مثال کے طور پر ، رسک: انعام کا تناسب 2: 1 کا تعین کرنے کا مطلب یہ ہے کہ ممکنہ منافع ممکنہ نقصان سے دوگنا ہے۔

  5. اے ٹی آر ٹریکنگ نقصان: ایک بار جب منافع خطرہ کی واپسی کی شرح سے پہلے سے طے شدہ حد تک پہنچ جاتا ہے تو ، نظام اے ٹی آر پر مبنی ٹریکنگ اسٹاپ نقصان کو متحرک کرسکتا ہے ، جس سے منافع کا ایک حصہ لاک ہوجاتا ہے جبکہ رجحان کو جاری رکھنے کی اجازت ملتی ہے۔

  6. دوسرا موقع تجارتجب ٹریڈنگ کی شروعات میں اسٹاپ نقصان یا ناکامی کا سامنا کرنا پڑتا ہے تو ، نظام خود بخود کھولنے کے وقفے کے دوران الٹ جانے والے مواقع کی تلاش کرتا ہے ، جس سے اس دن دو طرفہ تجارت کا امکان پیدا ہوتا ہے۔

اسٹریٹجک فوائد

  1. اعلی معیار کے مواقع پر توجہ مرکوزاس حکمت عملی کے ذریعے ، جعلی ٹرانزیکشنوں کو نمایاں طور پر کم کیا گیا ہے اور جیت کی شرح میں اضافہ ہوا ہے۔

  2. لچکدار داخلے کا طریقہ کار: فوری یا ریورس داخلہ کی حمایت کریں ، مختلف تجارتی طرزوں اور مارکیٹ کے حالات کے مطابق۔ فوری داخلہ مضبوط رجحانات کے لئے موزوں ہے ، جبکہ ریورس داخلہ بہتر داخلے کی قیمت حاصل کرسکتا ہے۔

  3. خطرے کے انتظام کے لئے خود کو اپنانا: متحرک اسٹاپ سیٹنگ جو خطرے کے مقابلے میں منافع کی ضرب پر مبنی ہے اس بات کو یقینی بناتا ہے کہ ہر تجارت میں یکساں خطرہ کی خصوصیات ہوں ، اور معیاری فنڈ مینجمنٹ ہو۔

  4. زیادہ سے زیادہ منافعاے ٹی آر کا اسٹاپ نقصان کا پتہ لگانے کا فنکشن مضبوط رجحانات کو برقرار رکھنے کی اجازت دیتا ہے ، جبکہ پہلے سے حاصل ہونے والے منافع کی حفاظت کرتا ہے ، اور جلد ہی دور ہونے سے بچتا ہے۔

  5. اعلی درجے کی نمائش: سسٹم میں وسیع پیمانے پر بصری معاون افعال فراہم کیے گئے ہیں ، بشمول وقفے کی نشاندہی ، توڑنے کی توثیق کا لیبل ، تجارت کی حیثیت کی نشاندہی ، داخلہ / نقصان / اسٹاپ مارکر وغیرہ ، جو تجارتی فیصلوں کو بہتر بناتا ہے۔

  6. غیر جانبدار پس منظر ڈیزائنحکمت عملی کا مکمل اطلاق:barstate.isconfirmedاس بات کو یقینی بنائیں کہ تمام فیصلے تصدیق شدہ قیمت کے اعداد و شمار پر مبنی ہوں ، پیش گوئی کے انحراف سے بچیں ، اور حقیقی تجارتی ماحول کے مطابق ہوں۔

  7. دوسرا موقع: دوسرا موقع ٹریڈنگ کی خصوصیت کو چالو کرنے کے ذریعے ، حکمت عملی مارکیٹ میں تبدیلیوں کو تیزی سے ڈھال سکتی ہے جب ابتدائی سمت میں غلطی کا فیصلہ کیا جاتا ہے ، الٹ کے مواقع کو پکڑ سکتی ہے ، اور فنڈز کے استعمال کی کارکردگی کو بہتر بناسکتی ہے۔

  8. سیشن مینجمنٹ کی اصلاح: سیشن کے اختتام کے لئے بلٹ ان آٹومیٹک پیج فنکشن اس بات کو یقینی بناتا ہے کہ راتوں رات پوزیشن نہ رکھی جائے ، اور راتوں رات خطرے کو کم کیا جائے۔

اسٹریٹجک رسک

  1. خطرے کی حد9: 09:30-09:35 کے دوران ، مارکیٹ میں غیر معمولی اتار چڑھاؤ ہوسکتا ہے ، جس کی وجہ سے بینڈ بہت وسیع یا بہت تنگ ہوجاتا ہے۔ بہت وسیع بینڈ زیادہ سے زیادہ اسٹاپ نقصان کا سبب بن سکتا ہے ، اور بہت تنگ بینڈ اکثر جعلی بریک کا سبب بن سکتا ہے۔ حل: غیر معمولی وقفوں کو خارج کرنے کے لئے کھلے وقفے کے سائز کے فلٹر کو بڑھانے پر غور کیا جاسکتا ہے۔ یا خاص دن (جیسے اہم معاشی اعداد و شمار کے اجراء کے دن) سے بچنے کے لئے تجارتی تاریخ کے فلٹر کو ایڈجسٹ کریں۔

  2. دھماکے کے بعد شدید واپسی کا خطرہ: ایک مؤثر بریک کے بعد ، مارکیٹ میں شدید واپسی ہوسکتی ہے ، جس کے نتیجے میں اسٹاپ نقصانات کو متحرک کرنے کے بعد مارکیٹ اپنی اصل سمت میں آگے بڑھ سکتی ہے۔ حل: زیادہ لچکدار اسٹاپ نقصان کی ترتیبات کا استعمال کرنے پر غور کریں ، جیسے کہ سیدھے فاصلے پر اسٹاپ۔ یا بہتر داخلے کی قیمت اور کم خطرے کی نمائش کے ل entry داخلے کو واپس کرنے کے لئے داخلے کے طریقہ کار کو ایڈجسٹ کریں۔

  3. سگنل کے معیار فلٹر کی ترتیب پر منحصر ہے: بریک کی توثیق شدہ شیڈ لائن فلٹرنگ اور فاصلہ فلٹرنگ پیرامیٹرز کی ترتیب سگنل کے معیار پر نمایاں اثر ڈالتی ہے۔ غلط پیرامیٹرز اچھے تجارتی مواقع کو فلٹر کرسکتے ہیں یا بہت زیادہ کم معیار کے سگنل وصول کرسکتے ہیں۔ حل: فلٹر کے پیرامیٹرز کو تاریخی پس منظر کے ذریعے بہتر بنائیں تاکہ مخصوص مارکیٹ اور اقسام کے لئے بہترین ترتیب مل سکے؛ مارکیٹ میں اتار چڑھاؤ کی متحرک حالت کے مطابق فلٹرنگ کے معیار کو ایڈجسٹ کرنے کے لئے خود کار طریقے سے پیرامیٹرز کا استعمال کرنے پر غور کریں۔

  4. ٹریکنگ سٹاپ نقصان پیرامیٹرز کی حساسیتاے ٹی آر ٹریکنگ اسٹاپ نقصانات کے پیرامیٹرز کی حد سے زیادہ سخت ہونے کی وجہ سے چھوٹے ریڈینس میں جلد ہی باہر نکلنے کا سبب بن سکتا ہے ، جبکہ حد سے زیادہ نرمی کی وجہ سے زیادہ منافع بخش واپسی کا سبب بن سکتا ہے۔ حل: ہدف کی قسم کی تاریخی اتار چڑھاؤ کی خصوصیات پر مبنی اے ٹی آر کے دورانیے اور ضرب کو ایڈجسٹ کریں۔ بیچوں کی صفائی کی حکمت عملی پر عمل درآمد پر غور کریں ، کچھ پوزیشنوں میں فکسڈ اسٹاپ اور کچھ پوزیشنوں میں ٹریکنگ اسٹاپ استعمال کریں۔

  5. ٹرانزیکشن فریکوئینسی کی حدحکمت عملی: ایک دن میں زیادہ سے زیادہ دو تجارتیں انجام دیں ((ابتدائی تجارت اور دوسرا موقع تجارت) ، اور آپ کو دن کے تمام مواقع سے بھرپور فائدہ اٹھانا ممکن نہیں ہوگا۔ حل: ایک توسیع کی حکمت عملی پر غور کریں ، دن کے دوسرے وقت کے اہم قیمتوں کے حلقوں کی نگرانی کریں۔ یا دوسرے تکنیکی اشارے کے ساتھ مل کر ایک جامع حکمت عملی بنائیں ، تاکہ تجارتی سگنل کے ذرائع میں اضافہ ہو۔

حکمت عملی کی اصلاح کی سمت

  1. کھلے بینڈوڈتھ سائیکل کو اپنانے: موجودہ حکمت عملی میں 5 منٹ کا فکسڈ اوپن فاصلہ استعمال کیا جاتا ہے ، مارکیٹ میں اتار چڑھاؤ کی متحرک تبدیلیوں کے مطابق فاصلہ کی لمبائی پر غور کیا جاسکتا ہے۔ کم اتار چڑھاؤ والی مارکیٹ میں فاصلہ کا وقت 3 منٹ تک کم کیا جاسکتا ہے ، جبکہ اعلی اتار چڑھاؤ والی مارکیٹ میں 10 منٹ تک بڑھایا جاسکتا ہے ، جو مختلف مارکیٹ کی حالتوں کے مطابق بہتر ہے۔

  2. مجموعی طور پر ٹرانسمیشن کی تصدیق: توڑ کی توثیق کے طریقہ کار میں ٹرانزیکشن فلٹرنگ کی شرائط میں اضافہ کریں ، جس میں ٹرانزیکشن کی ضرورت ہوتی ہے جب ٹرانزیکشن پچھلے چند ادوار کی اوسط ٹرانزیکشن سے نمایاں طور پر زیادہ ہو ، جس سے ٹرانزیکشن کی تاثیر میں اضافہ ہوتا ہے۔ یہ ٹرانزیکشن ٹرانزیکشن اور پچھلے N ادوار کی ٹرانزیکشن کی اوسط قدر کے تناسب کا حساب کرکے حاصل کیا جاسکتا ہے۔

  3. ملٹی ٹائم فریم تجزیہ: اعلی ٹائم فریموں کے رجحان کی سمت فلٹرنگ متعارف کروائیں ، صرف اس وقت داخل ہوں جب دن کی لکیر یا گھنٹہ کی لکیر کی سمت کی سمت ٹرانسمیشن کی سمت سے مطابقت رکھتی ہو ، تجارت کی جیت کی شرح میں اضافہ کریں۔ اعلی ٹائم فریم کے رجحانات کو سادہ حرکت پذیر اوسط سلائیڈ یا اعلی درجے کی رجحان اشارے کے ذریعہ طے کیا جاسکتا ہے۔

  4. فنڈ مینجمنٹ کو بہتر بنانا: متحرک پوزیشن اسکیل ایڈجسٹمنٹ میکانزم کا نفاذ ، جو تاریخی اتار چڑھاؤ ، موجودہ اکاؤنٹ کے سائز اور حالیہ کارکردگی کی بنیاد پر معاہدوں کی تعداد کو خود بخود ایڈجسٹ کرتا ہے ، تاکہ زیادہ ٹھیک ٹھیک خطرے کا کنٹرول ہو۔ مثال کے طور پر ، مسلسل منافع کے بعد پوزیشن میں بتدریج اضافہ اور مسلسل نقصان کے بعد پوزیشن میں کمی۔

  5. مربوط مشین لرننگ ماڈل: مشین لرننگ ماڈل متعارف کروائیں جس سے بریک کی کیفیت کا اندازہ لگایا جاسکے ، تاریخی اعداد و شمار کے ساتھ تربیت یافتہ ماڈل کے ذریعہ سب سے زیادہ کامیاب ہونے والے بریک کے نمونوں کی نشاندہی کی جاسکے۔ خصوصیات میں شامل ہوسکتے ہیں کھلنے کے فاصلے کا سائز ، مارکیٹ میں اتار چڑھاؤ ، پچھلے ٹریڈنگ دن کی قیمتوں کا رجحان ، مخصوص وقت کا نمونہ وغیرہ۔

  6. دوسرا موقع ٹریڈنگ کی منطق کو بڑھانا: دوسرے موقع کی تجارت کے محرکات کو بہتر بنانا ، نہ صرف ابتدائی تجارت کی ناکامی پر مبنی ، بلکہ مارکیٹ کی ساخت میں تبدیلی اور نئے متحرک اشارے کو بھی مدنظر رکھتے ہوئے ، دوسرے موقع کی تجارت کی کامیابی کی شرح کو بہتر بنانا۔

  7. ذاتی نوعیت کے پیرامیٹرز: مختلف تجارت شدہ اقسام کے ل optim موزوں پیرامیٹرز کا سیٹ تیار کریں ، ہر قسم کی منفرد اتار چڑھاؤ کی خصوصیات اور قیمت کے طرز عمل کو مدنظر رکھتے ہوئے۔ مثال کے طور پر ، زیادہ اتار چڑھاؤ والی اقسام کو فلٹر کی زیادہ نرمی کی ترتیبات اور زیادہ محتاط رسک ریٹرن کی ضرورت ہوسکتی ہے۔

  8. مارکیٹ کے جذبات کے انڈیکس: وی آئی ایکس انڈیکس یا مارکیٹ کے جذبات کے دیگر اشارے متعارف کروائیں ، مارکیٹ کے انتہائی جذبات کے دوران حکمت عملی کے پیرامیٹرز کو ایڈجسٹ کریں یا اعلی غیر یقینی صورتحال سے بچنے کے لئے تجارت کو عارضی طور پر بند کردیں۔

خلاصہ کریں۔

کھلنے کے وقفے میں توڑنے والی اے ٹی آر ٹریکنگ اسٹاپ اسٹریٹجی ایک اچھی طرح سے تشکیل شدہ مقداری ٹریڈنگ سسٹم ہے جو کھلنے کے وقفے میں توڑنے ، ذہین فلٹرنگ میکانزم ، لچکدار اندراج کے اختیارات اور اعلی درجے کی رسک مینجمنٹ کی خصوصیات کو چالاکی سے جوڑتا ہے۔ یہ حکمت عملی خاص طور پر امریکی اسٹاک اور فیوچر مارکیٹوں میں دن کے اندر تجارت کے لئے موزوں ہے ، جس میں کھلنے کے بعد دشاتمک توڑنے کو پکڑ کر منافع بخش بنایا جاتا ہے۔

اس حکمت عملی کی بنیادی قدر اس کے کثیر درجے کے توثیقی میکانزم اور رسک مینجمنٹ سسٹم میں ہے ، جس میں شیڈ لائن اور فاصلہ فلٹر کے ذریعہ جعلی توڑنے والے لین دین کو نمایاں طور پر کم کیا گیا ہے ، جبکہ خطرے کی واپسی کے تناسب کو ضرب دینے اور اے ٹی آر ٹریکنگ اسٹاپ نقصان کو یقینی بنانے کے لئے استعمال کیا جاتا ہے تاکہ خطرے کی نمائش اور منافع کی حفاظت کو یقینی بنایا جاسکے۔ دوسرا موقع ٹریڈنگ کی خصوصیت حکمت عملی میں موافقت اور اضافی منافع کے مواقع کو شامل کرتی ہے۔

اگرچہ اس حکمت عملی کے متعدد فوائد ہیں ، لیکن صارفین کو پیرامیٹرز کی اصلاح کی اہمیت پر بھی توجہ دینی چاہئے۔ مختلف مارکیٹوں اور اقسام کو زیادہ سے زیادہ اثر حاصل کرنے کے لئے ہدف کے مطابق ایڈجسٹمنٹ کی ضرورت پڑسکتی ہے۔ اس کے علاوہ ، تاجروں کو مشورہ دیا جاتا ہے کہ وہ اس حکمت عملی کو ایک مکمل تجارتی نظام کے حصے کے طور پر استعمال کریں ، جس میں مارکیٹ کے تجزیے اور خطرے کے انتظام کے وسیع تر اصولوں کے ساتھ مل کر استعمال کیا جائے۔

سفارشات پر عملدرآمد کی اصلاح کی طرف سے، خاص طور پر خود کار طریقے سے پیرامیٹرز، کثیر ٹائم فریم تجزیہ اور بہتر فنڈ مینجمنٹ سسٹم، اس حکمت عملی کو اس کی استحکام اور منافع بخش صلاحیت کو مزید بڑھانے کے لئے پیشہ ورانہ تاجروں کے ٹول کٹ میں ایک طاقتور آلہ بننے کی صلاحیت ہے.

حکمت عملی کا ماخذ کوڈ
/*backtest
start: 2025-07-18 00:00:00
end: 2025-07-30 00:00:00
period: 30m
basePeriod: 30m
exchanges: [{"eid":"Futures_Binance","currency":"ETH_USDT"}]
*/

//@version=5
strategy("Casper SMC 5min ORB - Roboquant AI", overlay=true, default_qty_type=strategy.fixed, default_qty_value=1, max_bars_back=500, calc_on_order_fills=true, calc_on_every_tick=false, initial_capital=50000, currency=currency.USD)

// === STRATEGY SETTINGS ===
// Risk Management
contracts = input.int(1, "Contracts", minval=1, group="Risk Management")
risk_multiplier = input.float(2.0, "Risk:Reward Multiplier", minval=0.5, maxval=10.0, group="Risk Management")
sl_points = input.int(2, "Stop Loss Points Below/Above Breakout Candle", minval=1, group="Risk Management")

// Entry Settings
entry_type = input.string("Instant", "Entry Type", options=["Retracement", "Instant"], group="Entry Settings")
retracement_percent = input.float(50.0, "Retracement % of Breakout Candle Body", minval=10.0, maxval=90.0, group="Entry Settings")

// Stop Loss Settings
sl_type = input.string("Opposite Range", "Stop Loss Type", options=["Breakout Candle", "Opposite Range"], group="Stop Loss Settings")

// Second Chance Trade Settings
enable_second_chance = input.bool(false, "Enable Second Chance Trade", group="Second Chance Trade")
second_chance_info = input.string("If initial SL is hit, allow opposite breakout trade", "Info: Second Chance Logic", group="Second Chance Trade")

// Breakout Filter Settings
use_wick_filter = input.bool(false, "Use Wick Filter", group="Breakout Filter")
max_wick_percent = input.float(50.0, "Max Wick % of Candle Body", minval=10.0, maxval=200.0, group="Breakout Filter")

// Breakout Distance Filters
use_breakout_distance_filter = input.bool(true, "Use Breakout Distance Filter", group="Breakout Distance Filter")
min_breakout_multiplier = input.float(0.1, "Min Breakout Distance (OR Size * X)", minval=0.0, maxval=3.0, group="Breakout Distance Filter")
max_breakout_multiplier = input.float(1.6, "Max Breakout Distance (OR Size * X)", minval=0.5, maxval=5.0, group="Breakout Distance Filter")

// Trailing Stop Loss Settings
use_trailing_sl = input.bool(false, "Use Trailing Stop Loss", group="Trailing Stop Loss")
profit_r_multiplier = input.float(1.0, "Start Trailing After X R Profit", minval=0.5, maxval=5.0, group="Trailing Stop Loss")
atr_length = input.int(14, "ATR Length", minval=1, maxval=50, group="Trailing Stop Loss")
atr_multiplier = input.float(1.0, "ATR Multiplier for Trailing", minval=0.5, maxval=5.0, group="Trailing Stop Loss")

// Session Management
or_start_hour = input.int(9, "Opening Range Start Hour", minval=0, maxval=23, group="Session Management")
or_start_minute = input.int(30, "Opening Range Start Minute", minval=0, maxval=59, group="Session Management")
or_end_minute = input.int(35, "Opening Range End Minute", minval=0, maxval=59, group="Session Management")
session_timezone = input.string("America/New_York", "Session Timezone", group="Session Management")
force_session_close = input.bool(true, "Force Close at Session End", group="Session Management")
session_end_hour = input.int(16, "Session End Hour", minval=0, maxval=23, group="Session Management")
session_end_minute = input.int(0, "Session End Minute", minval=0, maxval=59, group="Session Management")

// Day of Week Trading Filters
trade_monday = input.bool(true, "Trade on Monday", group="Day of Week Filters")
trade_tuesday = input.bool(true, "Trade on Tuesday", group="Day of Week Filters")
trade_wednesday = input.bool(true, "Trade on Wednesday", group="Day of Week Filters")
trade_thursday = input.bool(true, "Trade on Thursday", group="Day of Week Filters")
trade_friday = input.bool(true, "Trade on Friday", group="Day of Week Filters")

// Visual Settings
high_line_color = input.color(color.green, title="Opening Range High Line Color", group="Visual Settings")
low_line_color = input.color(color.red, title="Opening Range Low Line Color", group="Visual Settings")

// Label Control Settings
show_trading_disabled_labels = input.bool(false, "Show Trading Disabled Labels", group="Label Controls")
show_breakout_validation_labels = input.bool(true, "Show Breakout Validation Labels", group="Label Controls")
show_second_chance_labels = input.bool(false, "Show Second Chance Labels", group="Label Controls")
show_trade_status_labels = input.bool(false, "Show Trade Status Labels", group="Label Controls")
show_entry_labels = input.bool(false, "Show Entry Labels", group="Label Controls")
show_sl_tp_labels = input.bool(false, "Show Stop Loss / Take Profit Labels", group="Label Controls")

// === VARIABLES ===
// ATR for trailing stop loss
atr = ta.atr(atr_length)

// === NYSE OPENING RANGE LOGIC ===
// FIXED: Using configurable hour/minute inputs with timezone
current_time = time(timeframe.period, "0000-2400:23456", session_timezone)
current_hour = hour(current_time, session_timezone)
current_minute = minute(current_time, session_timezone)
is_opening_range = current_hour == or_start_hour and current_minute >= or_start_minute and current_minute <= or_end_minute

// Check if we're at the start of a new trading day - FIXED: More reliable detection
is_new_day = ta.change(time("1D"))

// ADDED: Check if trading is allowed on current day of week (using session timezone)
current_day = dayofweek(current_time, session_timezone)
is_trading_day_allowed = (current_day == dayofweek.monday and trade_monday) or (current_day == dayofweek.tuesday and trade_tuesday) or (current_day == dayofweek.wednesday and trade_wednesday) or (current_day == dayofweek.thursday and trade_thursday) or (current_day == dayofweek.friday and trade_friday)

// Variables to store opening range high and low for current day
var float or_high = na
var float or_low = na
var bool lines_drawn = false
var bool breakout_occurred = false
var float breakout_candle_high = na
var float breakout_candle_low = na
var float breakout_price = na
var string breakout_direction = na
var int or_start_bar = na  // ADDED: Store the bar index when opening range starts

// ADDED: Second chance trade variables
var bool first_trade_sl_hit = false
var string first_trade_direction = na
var bool second_chance_available = false
var bool second_trade_taken = false
var bool daily_trades_complete = false  // ADDED: Prevent more than 2 trades per day

// Reset variables at the start of each trading day
if is_new_day
    or_high := na
    or_low := na
    lines_drawn := false
    breakout_occurred := false
    breakout_candle_high := na
    breakout_candle_low := na
    breakout_price := na
    breakout_direction := na
    or_start_bar := na  // ADDED: Reset opening range start bar
    // ADDED: Reset second chance variables
    first_trade_sl_hit := false
    first_trade_direction := na
    second_chance_available := false
    second_trade_taken := false
    daily_trades_complete := false  // ADDED: Reset trade limit

// Capture opening range data during 09:30-09:35 EST
if is_opening_range
    if na(or_high) or na(or_low)
        or_high := high
        or_low := low
        or_start_bar := bar_index  // ADDED: Store the bar index when opening range starts
    else
        or_high := math.max(or_high, high)
        or_low := math.min(or_low, low)

// Draw lines when we're past the opening range and haven't drawn yet
if not is_opening_range and not na(or_high) and not na(or_low) and not na(or_start_bar) and not lines_drawn
    // FIXED: Lines start from the actual opening range start time and extend forward
    start_x = or_start_bar
    end_x = bar_index + 50  // Extend lines forward for visibility
    

    
    lines_drawn := true
    
    // ADDED: Show visual indicator if trading is disabled for current day
    if not is_trading_day_allowed and show_trading_disabled_labels
        day_name = current_day == dayofweek.monday ? "Monday" :
                   current_day == dayofweek.tuesday ? "Tuesday" :
                   current_day == dayofweek.wednesday ? "Wednesday" :
                   current_day == dayofweek.thursday ? "Thursday" :
                   current_day == dayofweek.friday ? "Friday" : "Weekend"
        label.new(x=bar_index, y=(or_high + or_low) / 2, text="Trading Disabled\n" + day_name, color=color.gray, textcolor=color.white, style=label.style_label_center, size=size.normal)

// Check for breakouts after opening range is complete (only first breakout of the day)
// FIXED: Added barstate.isconfirmed to avoid lookahead bias
if barstate.isconfirmed and not is_opening_range and not na(or_high) and not na(or_low) and lines_drawn and not breakout_occurred and not daily_trades_complete and is_trading_day_allowed
    // Calculate candle body and wick percentages
    candle_body = math.abs(close - open)
    top_wick = high - math.max(open, close)
    bottom_wick = math.min(open, close) - low
    top_wick_percent = candle_body > 0 ? (top_wick / candle_body) * 100 : 0
    bottom_wick_percent = candle_body > 0 ? (bottom_wick / candle_body) * 100 : 0
    
    // ADDED: Calculate opening range size for distance filters
    or_size = or_high - or_low
    
    // Check for first breakout above opening range high
    if close > or_high
        // FIXED: Mark breakout as occurred FIRST (this is THE breakout candle)
        breakout_occurred := true
        breakout_candle_high := high
        breakout_candle_low := low
        breakout_price := close
        breakout_direction := "long"
        
        // ADDED: Validate this specific breakout candle against distance filter
        breakout_distance_valid = true
        if use_breakout_distance_filter
            min_breakout_level = or_high + (or_size * min_breakout_multiplier)
            max_breakout_level = or_high + (or_size * max_breakout_multiplier)
            breakout_distance_valid := close >= min_breakout_level and close <= max_breakout_level
        
        // Apply wick filter for long breakouts
        wick_filter_valid = not use_wick_filter or top_wick_percent <= max_wick_percent
        
        // Show appropriate label based on validation results
        if show_breakout_validation_labels
            if wick_filter_valid and breakout_distance_valid
                label.new(x=bar_index, y=high, text="VALID", color=high_line_color, textcolor=color.white, style=label.style_label_down, size=size.tiny)
            else
                label.new(x=bar_index, y=high, text="INVALID", color=color.gray, textcolor=color.white, style=label.style_label_down, size=size.tiny)
        
        // Mark breakout as invalid so no trade will be placed (regardless of label setting)
        if not (wick_filter_valid and breakout_distance_valid)
            breakout_direction := "invalid"
    
    // Check for first breakout below opening range low  
    else if close < or_low
        // FIXED: Mark breakout as occurred FIRST (this is THE breakout candle)
        breakout_occurred := true
        breakout_candle_high := high
        breakout_candle_low := low
        breakout_price := close
        breakout_direction := "short"
        
        // ADDED: Validate this specific breakout candle against distance filter
        breakout_distance_valid = true
        if use_breakout_distance_filter
            min_breakout_level = or_low - (or_size * min_breakout_multiplier)
            max_breakout_level = or_low - (or_size * max_breakout_multiplier)
            breakout_distance_valid := close <= min_breakout_level and close >= max_breakout_level
        
        // Apply wick filter for short breakouts
        wick_filter_valid = not use_wick_filter or bottom_wick_percent <= max_wick_percent
        
        // Show appropriate label based on validation results
        if show_breakout_validation_labels
            if wick_filter_valid and breakout_distance_valid
                label.new(x=bar_index, y=low, text="VALID", color=low_line_color, textcolor=color.white, style=label.style_label_up, size=size.tiny)
            else
                label.new(x=bar_index, y=low, text="INVALID", color=color.gray, textcolor=color.white, style=label.style_label_up, size=size.tiny)
        
        // Mark breakout as invalid so no trade will be placed (regardless of label setting)
        if not (wick_filter_valid and breakout_distance_valid)
            breakout_direction := "invalid"

// ADDED: Check for second chance breakout (opposite direction after initial SL hit)
// FIXED: Added barstate.isconfirmed to avoid lookahead bias
if barstate.isconfirmed and not is_opening_range and not na(or_high) and not na(or_low) and lines_drawn and second_chance_available and not second_trade_taken and not daily_trades_complete and is_trading_day_allowed
    // Calculate candle body and wick percentages
    candle_body = math.abs(close - open)
    top_wick = high - math.max(open, close)
    bottom_wick = math.min(open, close) - low
    top_wick_percent = candle_body > 0 ? (top_wick / candle_body) * 100 : 0
    bottom_wick_percent = candle_body > 0 ? (bottom_wick / candle_body) * 100 : 0
    
    // ADDED: Calculate opening range size for distance filters
    or_size = or_high - or_low
    
    // If first trade was LONG and failed, look for SHORT breakout
    if first_trade_direction == "long" and close < or_low
        // FIXED: Mark second chance breakout as taken FIRST
        second_trade_taken := true
        second_chance_available := false
        breakout_candle_high := high
        breakout_candle_low := low
        breakout_price := close
        breakout_direction := "short"
        
        // ADDED: Validate this specific breakout candle against distance filter
        breakout_distance_valid = true
        if use_breakout_distance_filter
            min_breakout_level = or_low - (or_size * min_breakout_multiplier)
            max_breakout_level = or_low - (or_size * max_breakout_multiplier)
            breakout_distance_valid := close <= min_breakout_level and close >= max_breakout_level
        
        // Apply wick filter for short breakouts
        wick_filter_valid = not use_wick_filter or bottom_wick_percent <= max_wick_percent
        
        // Show appropriate label based on validation results
        if show_second_chance_labels
            if wick_filter_valid and breakout_distance_valid
                label.new(x=bar_index, y=low, text="2nd Chance\nOR Low Break\nVALID", color=color.orange, textcolor=color.white, style=label.style_label_up, size=size.tiny)
            else
                label.new(x=bar_index, y=low, text="2nd Chance\nOR Low Break\nINVALID", color=color.gray, textcolor=color.white, style=label.style_label_up, size=size.tiny)
        
        // Mark breakout as invalid so no trade will be placed (regardless of label setting)
        if not (wick_filter_valid and breakout_distance_valid)
            breakout_direction := "invalid"
    
    // If first trade was SHORT and failed, look for LONG breakout
    else if first_trade_direction == "short" and close > or_high
        // FIXED: Mark second chance breakout as taken FIRST
        second_trade_taken := true
        second_chance_available := false
        breakout_candle_high := high
        breakout_candle_low := low
        breakout_price := close
        breakout_direction := "long"
        
        // ADDED: Validate this specific breakout candle against distance filter
        breakout_distance_valid = true
        if use_breakout_distance_filter
            min_breakout_level = or_high + (or_size * min_breakout_multiplier)
            max_breakout_level = or_high + (or_size * max_breakout_multiplier)
            breakout_distance_valid := close >= min_breakout_level and close <= max_breakout_level
        
        // Apply wick filter for long breakouts
        wick_filter_valid = not use_wick_filter or top_wick_percent <= max_wick_percent
        
        // Show appropriate label based on validation results
        if show_second_chance_labels
            if wick_filter_valid and breakout_distance_valid
                label.new(x=bar_index, y=high, text="2nd Chance\nOR High Break\nVALID", color=color.orange, textcolor=color.white, style=label.style_label_down, size=size.tiny)
            else
                label.new(x=bar_index, y=high, text="2nd Chance\nOR High Break\nINVALID", color=color.gray, textcolor=color.white, style=label.style_label_down, size=size.tiny)
        
        // Mark breakout as invalid so no trade will be placed (regardless of label setting)
        if not (wick_filter_valid and breakout_distance_valid)
            breakout_direction := "invalid"

// === STRATEGY LOGIC ===
// Check if we have a breakout and place retracement entry orders
var bool entry_placed = false
var bool second_entry_placed = false  // ADDED: Track second trade entry separately
var float entry_price = na
var float stop_loss = na
var float take_profit = na
var float trailing_stop = na
var bool trailing_active = false
var float initial_risk = na
var bool trailing_started = false
var string current_entry_id = na  // FIXED: Track which entry ID we're using

// Arrays to store historical trade boxes
var array<box> historical_trade_boxes = array.new<box>()
var array<box> historical_sl_boxes = array.new<box>()
var array<box> historical_tp_boxes = array.new<box>()

// Variables to track current active trade boxes for extending to exit
var box current_profit_box = na
var box current_sl_box = na

// ADDED: General position close detection for extending boxes - Handle timing issues
if barstate.isconfirmed and strategy.position_size == 0 and strategy.position_size[1] != 0
    // Extend trade visualization boxes to exact exit point when any position closes
    if not na(current_profit_box)
        // Ensure minimum 8 bars width or extend to current bar, whichever is longer
        box_left = box.get_left(current_profit_box)
        min_right = box_left + 8
        final_right = math.max(min_right, bar_index)
        box.set_right(current_profit_box, final_right)
        current_profit_box := na  // Clear reference after extending
    if not na(current_sl_box)
        // Ensure minimum 8 bars width or extend to current bar, whichever is longer
        box_left = box.get_left(current_sl_box)
        min_right = box_left + 8
        final_right = math.max(min_right, bar_index)
        box.set_right(current_sl_box, final_right)
        current_sl_box := na  // Clear reference after extending

// ADDED: Backup safety check - extend boxes if position is closed but boxes still active
if not na(current_profit_box) and strategy.position_size == 0
    box_left = box.get_left(current_profit_box)
    min_right = box_left + 8
    final_right = math.max(min_right, bar_index)
    box.set_right(current_profit_box, final_right)
    current_profit_box := na
if not na(current_sl_box) and strategy.position_size == 0
    box_left = box.get_left(current_sl_box)
    min_right = box_left + 8
    final_right = math.max(min_right, bar_index)
    box.set_right(current_sl_box, final_right)
    current_sl_box := na

// Reset entry flag on new day
if is_new_day
    entry_placed := false
    second_entry_placed := false  // ADDED: Reset second entry flag
    entry_price := na
    stop_loss := na
    take_profit := na
    trailing_stop := na
    trailing_active := false
    initial_risk := na
    trailing_started := false
    current_entry_id := na  // FIXED: Reset entry ID
    current_profit_box := na  // ADDED: Reset current trade boxes
    current_sl_box := na

// SIMPLIFIED: Detect when position closes to enable second chance (FIXED for lookahead bias)
if barstate.isconfirmed and strategy.position_size == 0 and strategy.position_size[1] != 0 and entry_placed and not first_trade_sl_hit
    // A position just closed and we had an active trade
    if enable_second_chance and not second_trade_taken
        // Simplified logic - if position closed, enable second chance
        first_trade_sl_hit := true
        first_trade_direction := breakout_direction
        second_chance_available := true
        
        // Reset variables for potential second trade
        entry_price := na
        trailing_stop := na
        trailing_active := false
        initial_risk := na
        trailing_started := false
        current_entry_id := na
        
        // Add visual marker
        if show_trade_status_labels
            label.new(x=bar_index, y=close, text="Trade Closed\nSecond Chance Available", color=color.yellow, textcolor=color.black, style=label.style_label_down, size=size.tiny)
    else
        // Second chance not enabled or already taken - mark day complete
        daily_trades_complete := true

// ADDED: Handle case where first breakout was invalid (no trade placed)
if breakout_occurred and breakout_direction == "invalid" and enable_second_chance and not first_trade_sl_hit
    // First breakout was invalid, enable second chance immediately
    first_trade_sl_hit := true
    // Determine what direction the invalid breakout was
    first_trade_direction := breakout_price > or_high ? "long" : "short"
    second_chance_available := true
    if show_trade_status_labels
        label.new(x=bar_index + 1, y=(or_high + or_low) / 2, text="First Breakout Invalid\nSecond Chance Available", color=color.yellow, textcolor=color.black, style=label.style_label_center, size=size.tiny)

// REMOVED: Complex historical box cleanup to avoid lookahead bias
// Historical boxes will be cleaned up automatically by Pine Script's runtime

// Place entry orders after breakout - FIXED: Add barstate.isconfirmed for consistency
if barstate.isconfirmed and not daily_trades_complete and is_trading_day_allowed and ((breakout_occurred and not entry_placed and not na(breakout_candle_high) and breakout_direction != "invalid") or (second_trade_taken and not second_entry_placed and not na(breakout_candle_high) and breakout_direction != "invalid"))
    // For long breakout
    if breakout_direction == "long"
        // Calculate stop loss based on selected method
        if sl_type == "Breakout Candle"
            stop_loss := breakout_candle_low - (sl_points * syminfo.mintick)
        else
            // Use opposite side of opening range (below opening range low)
            stop_loss := or_low - (sl_points * syminfo.mintick)
        
        if entry_type == "Retracement"
            // Calculate retracement entry price (x% of breakout candle body)
            breakout_candle_body = breakout_candle_high - breakout_candle_low
            retracement_amount = breakout_candle_body * (retracement_percent / 100)
            entry_price := breakout_candle_high - retracement_amount
            
            // FIXED: Store the entry ID we're using (differentiate first vs second chance)
            current_entry_id := second_trade_taken ? "Long Retracement 2nd" : "Long Retracement"
            
            // Place buy limit order at retracement level
            strategy.entry(current_entry_id, strategy.long, limit=entry_price, qty=contracts)
            
            // Add visual markers
            if show_entry_labels
                entry_label_text = second_trade_taken ? "BUY LIMIT (2nd)\n" + str.tostring(entry_price, "#.##") : "BUY LIMIT\n" + str.tostring(entry_price, "#.##")
                label.new(x=bar_index, y=entry_price, text=entry_label_text, color=color.green, textcolor=color.white, style=label.style_label_up, size=size.tiny)
        else
            // Immediate entry at breakout candle close
            entry_price := breakout_price
            
            // FIXED: Store the entry ID we're using (differentiate first vs second chance)
            current_entry_id := second_trade_taken ? "Instant Long 2nd" : "Instant Long"
            
            // Place buy market order
            strategy.entry(current_entry_id, strategy.long, qty=contracts)
            
            // Add visual markers
            if show_entry_labels
                entry_label_text = second_trade_taken ? "BUY MARKET (2nd)\n" + str.tostring(entry_price, "#.##") : "BUY MARKET\n" + str.tostring(entry_price, "#.##")
                label.new(x=bar_index, y=entry_price, text=entry_label_text, color=color.green, textcolor=color.white, style=label.style_label_up, size=size.tiny)
        
        // Calculate take profit based on risk:reward
        risk_size = entry_price - stop_loss
        take_profit := entry_price + (risk_size * risk_multiplier)
        
        // FIXED: Set exit orders with proper entry ID and always include initial stop loss
        if use_trailing_sl
            // Initialize trailing stop and calculate initial risk
            trailing_stop := stop_loss
            trailing_active := true
            initial_risk := math.abs(entry_price - stop_loss)
            trailing_started := false
            // FIXED: Always set initial stop loss, even with trailing enabled
            exit_id = second_trade_taken ? "Long Exit 2nd" : "Long Exit"
            strategy.exit(exit_id, current_entry_id, stop=stop_loss, limit=take_profit)
        else
            // FIXED: Use stored entry ID
            exit_id = second_trade_taken ? "Long Exit 2nd" : "Long Exit"
            strategy.exit(exit_id, current_entry_id, stop=stop_loss, limit=take_profit)
        
        // Create trade visualization boxes (TradingView style) - FIXED: Minimum 8 bars width
        // Blue profit zone box (from entry to take profit)

        
        // Store trade boxes for historical display - FIXED: Remove time usage
        array.push(historical_trade_boxes, current_profit_box)
        array.push(historical_sl_boxes, current_sl_box)
        array.push(historical_tp_boxes, na) // No TP box for long trades
        
        // Add stop loss and take profit markers
        if show_sl_tp_labels
            label.new(x=bar_index, y=stop_loss, text="SL\n" + str.tostring(stop_loss, "#.##"), color=color.red, textcolor=color.white, style=label.style_label_down, size=size.tiny)
            label.new(x=bar_index, y=take_profit, text="TP\n" + str.tostring(take_profit, "#.##"), color=color.blue, textcolor=color.white, style=label.style_label_down, size=size.tiny)
        
        // ADDED: Set the appropriate entry flag based on which trade this is
        if second_trade_taken
            second_entry_placed := true
            daily_trades_complete := true
        else
            entry_placed := true
    
    // For short breakout
    else if breakout_direction == "short"
        // Calculate stop loss based on selected method
        if sl_type == "Breakout Candle"
            stop_loss := breakout_candle_high + (sl_points * syminfo.mintick)
        else
            // Use opposite side of opening range (above opening range high)
            stop_loss := or_high + (sl_points * syminfo.mintick)
        
        if entry_type == "Retracement"
            // Calculate retracement entry price (x% of breakout candle body)
            breakout_candle_body = breakout_candle_high - breakout_candle_low
            retracement_amount = breakout_candle_body * (retracement_percent / 100)
            entry_price := breakout_candle_low + retracement_amount
            
            // FIXED: Store the entry ID we're using (differentiate first vs second chance)
            current_entry_id := second_trade_taken ? "Short Retracement 2nd" : "Short Retracement"
            
            // Place sell limit order at retracement level
            strategy.entry(current_entry_id, strategy.short, limit=entry_price, qty=contracts)
            
            // Add visual markers
            if show_entry_labels
                entry_label_text = second_trade_taken ? "SELL LIMIT (2nd)\n" + str.tostring(entry_price, "#.##") : "SELL LIMIT\n" + str.tostring(entry_price, "#.##")
                label.new(x=bar_index, y=entry_price, text=entry_label_text, color=color.red, textcolor=color.white, style=label.style_label_down, size=size.tiny)
        else
            // Immediate entry at breakout candle close
            entry_price := breakout_price
            
            // FIXED: Store the entry ID we're using (differentiate first vs second chance)
            current_entry_id := second_trade_taken ? "Instant 2nd" : "Instant Short"
            
            // Place sell market order
            strategy.entry(current_entry_id, strategy.short, qty=contracts)
            
            // Add visual markers
            if show_entry_labels
                entry_label_text = second_trade_taken ? "SELL MARKET (2nd)\n" + str.tostring(entry_price, "#.##") : "SELL MARKET\n" + str.tostring(entry_price, "#.##")
                label.new(x=bar_index, y=entry_price, text=entry_label_text, color=color.red, textcolor=color.white, style=label.style_label_down, size=size.tiny)
        
        // Calculate take profit based on risk:reward
        risk_size = stop_loss - entry_price
        take_profit := entry_price - (risk_size * risk_multiplier)
        
        // FIXED: Set exit orders with proper entry ID and always include initial stop loss
        if use_trailing_sl
            // Initialize trailing stop and calculate initial risk
            trailing_stop := stop_loss
            trailing_active := true
            initial_risk := math.abs(entry_price - stop_loss)
            trailing_started := false
            // FIXED: Always set initial stop loss, even with trailing enabled
            exit_id = second_trade_taken ? "Short Exit 2nd" : "Short Exit"
            strategy.exit(exit_id, current_entry_id, stop=stop_loss, limit=take_profit)
        else
            // FIXED: Use stored entry ID
            exit_id = second_trade_taken ? "Short Exit 2nd" : "Short Exit"
            strategy.exit(exit_id, current_entry_id, stop=stop_loss, limit=take_profit)
        
        // Create trade visualization boxes (TradingView style) - FIXED: Minimum 8 bars width

        
        // Store trade boxes for historical display - FIXED: Remove time usage
        array.push(historical_trade_boxes, current_profit_box)
        array.push(historical_sl_boxes, current_sl_box)
        array.push(historical_tp_boxes, na) // No TP box for short trades
        
        // Add stop loss and take profit markers
        if show_sl_tp_labels
            label.new(x=bar_index, y=stop_loss, text="SL\n" + str.tostring(stop_loss, "#.##"), color=color.red, textcolor=color.white, style=label.style_label_up, size=size.tiny)
            label.new(x=bar_index, y=take_profit, text="TP\n" + str.tostring(take_profit, "#.##"), color=color.blue, textcolor=color.white, style=label.style_label_up, size=size.tiny)
        
        // ADDED: Set the appropriate entry flag based on which trade this is
        if second_trade_taken
            second_entry_placed := true
            daily_trades_complete := true
        else
            entry_placed := true

// === TRAILING STOP LOGIC ===
// FIXED: Proper trailing stop loss management
if use_trailing_sl and trailing_active and strategy.position_size != 0 and not na(current_entry_id)
    if strategy.position_size > 0  // Long position
        // Calculate current unrealized profit in points
        current_profit = close - entry_price
        profit_r = current_profit / initial_risk
        
        // Check if we should start trailing (after X R profit)
        if not trailing_started and profit_r >= profit_r_multiplier
            trailing_started := true
            // Start trailing from a level that's better than the initial stop
            trailing_stop := math.max(trailing_stop, close - (atr * atr_multiplier))
        
        // Update trailing stop if trailing has started
        if trailing_started
            // Calculate new trailing stop using ATR
            potential_new_stop = close - (atr * atr_multiplier)
            // Only move stop loss up (never down) and ensure it's better than initial SL
            if potential_new_stop > trailing_stop and potential_new_stop > stop_loss
                trailing_stop := potential_new_stop
                // Update the exit order with new trailing stop
                exit_id = second_trade_taken ? "Long Exit 2nd" : "Long Exit"
                strategy.exit(exit_id, current_entry_id, stop=trailing_stop, limit=take_profit)
    
    else if strategy.position_size < 0  // Short position
        // Calculate current unrealized profit in points
        current_profit = entry_price - close
        profit_r = current_profit / initial_risk
        
        // Check if we should start trailing (after X R profit)
        if not trailing_started and profit_r >= profit_r_multiplier
            trailing_started := true
            // Start trailing from a level that's better than the initial stop
            trailing_stop := math.min(trailing_stop, close + (atr * atr_multiplier))
        
        // Update trailing stop if trailing has started
        if trailing_started
            // Calculate new trailing stop using ATR
            potential_new_stop = close + (atr * atr_multiplier)
            // Only move stop loss down (never up) and ensure it's better than initial SL
            if potential_new_stop < trailing_stop and potential_new_stop < stop_loss
                trailing_stop := potential_new_stop
                // Update the exit order with new trailing stop
                exit_id = second_trade_taken ? "Short Exit 2nd" : "Short Exit"
                strategy.exit(exit_id, current_entry_id, stop=trailing_stop, limit=take_profit)

// === SESSION END CLOSE ===
// Force close all positions at configured session end time (optional)
// FIXED: Using configurable hour/minute with timezone
if force_session_close and current_hour == session_end_hour and current_minute == session_end_minute
    // ADDED: Extend boxes immediately before session close to prevent timing issues
    if not na(current_profit_box)
        // Ensure minimum 8 bars width or extend to current bar, whichever is longer
        box_left = box.get_left(current_profit_box)
        min_right = box_left + 8
        final_right = math.max(min_right, bar_index)
        box.set_right(current_profit_box, final_right)
        current_profit_box := na  // Clear reference after extending
    if not na(current_sl_box)
        // Ensure minimum 8 bars width or extend to current bar, whichever is longer
        box_left = box.get_left(current_sl_box)
        min_right = box_left + 8
        final_right = math.max(min_right, bar_index)
        box.set_right(current_sl_box, final_right)
        current_sl_box := na  // Clear reference after extending
    
    strategy.close_all(comment="Session End Close")

// === ALERTS ===
alert_once_long = (strategy.position_size > 0) and (strategy.position_size[1] == 0)
alert_once_short = (strategy.position_size < 0) and (strategy.position_size[1] == 0)

alertcondition(alert_once_long, title="Long Entry (Once)", message="Long Entry Signal")
alertcondition(alert_once_short, title="Short Entry (Once)", message="Short Entry Signal")