فرمول نویسی شورت کال باترفلای | Short Call Butterfly در دیده بان
آموزش فرمولنویسی شورت کال باترفلای در دیدهبان: حلقه optionSE برای K2 و K3، اعتبار خالص با سرخط درست، سه ناحیه کارمزد اعمال، دو سربهسر، وجه تضمین پایه K1 و pos.add.
این مقاله برای کسانی است که میخواهند خودشان در دیدهبان با فرمولنویسی ترکیبهای شورت کال باترفلای (Short Call Butterfly) را پیدا کنند: فروش 1 کال با اعمال پایین (K1)، خرید 2 کال با اعمال میانی (K2) و فروش 1 کال با اعمال بالا (K3) روی یک نماد و یک سررسید، با شرط تقارن K2 − K1 = K3 − K2.
منطق کد: از ردیف جاری بهعنوان K1 شروع کنید، با تابع optionSE اعمالهای بالاتر را برای K2 و K3 پیدا کنید، اعتبار خالص دریافتی را با سمت درست سرخطها حساب کنید و سپس سود دو دنباله، حداکثر زیان، دو سربهسر و سرمایهٔ درگیر را بسازید. مبانی مفهومی در شورت کال باترفلای و راهنمای اسکنر آماده در پیادهسازی در دیدهبان آمده است.
highOption = optionSE(j) با j > i = کال فروختهشده @ K3 (بال بالا)
چون optionSE بهطور پیشفرض فقط قراردادهای همنوعِ ردیف جاری را برمیگرداند، کافی است در ابتدای فرمول یکبار option.type !== 'call' را رد کنید:
if (option.type !== 'call') {
if (FILTER_RESULT === true) return false;
return '';
}
// پایهٔ K1 فروخته میشود؛ بدون سرخط تقاضا هیچ ترکیبی معتبر نیست
if (option.ti.buy1Volume === 0 || option.ti.buy1Price === 0) {
if (FILTER_RESULT === true) return false;
return '';
}
شرطهایی که به متغیر حلقه وابسته نیستند (مثل سرخط خودِ ردیف) را بیرون حلقه بگذارید تا در هر تکرار دوباره ارزیابی نشوند.
اعتبار خالص با سمت درست سرخط
هر پایه باید با قیمتی محاسبه شود که واقعاً با آن معامله میشود: پایههای فروش با سرخط تقاضا (buy1Price) و پایهٔ خرید با سرخط عرضه (sell1Price). خطای رایج، استفاده از lastPrice برای هر سه پایه است که اعتبار را خوشبینانه نشان میدهد.
فروش با buy1Price و خرید با sell1Price — با قیمت پایانی، اعتبار خالص بزرگتر درمیآید و ردیفهای غیرقابلاجرا بالای فهرست مینشینند.
چون بدنه دو قرارداد است، حجم سرخط عرضهٔ K2 باید حداقل 2 باشد (midOption.ti.sell1Volume < 2 را رد کنید). دربارهٔ نرخها: کارمزد معاملات اختیار معامله.
سه ناحیهٔ کارمزد اعمال — مهمترین نکتهٔ این استراتژی
در منابع خارجی حداکثر سود شورت باترفلای «همان اعتبار خالص دریافتی» معرفی میشود. این جمله در بازار ایران فقط برای دنبالهٔ پایین (زیر K1) درست است؛ بالای K3 هر سه پایه ITM میشوند و اعمال هر چهار قرارداد کارمزد دارد — و کارمزد اعمال فروشنده روی سهام 0.55٪ ارزش اعمال است (روی صندوقها/ETF حدود 0.05٪). یعنی دو پایهٔ فروش K1 و K3 با هم میتوانند بیش از 1٪ ارزش قرارداد کارمزد بسازند.
کارمزد اعمال در چهار ناحیهٔ قیمت، چهار مقدار متفاوت دارد — پس در فرمول باید تابعی از قیمت فرضی باشد، نه یک عدد ثابت.«حداکثر سود = اعتبار خالص» فقط زیر K1 درست است؛ بالای K3 چهار کارمزد اعمال از آن کم میشود. سودِ قابل اتکا کمترینِ دو دنباله است.
ناحیهٔ قیمت پایه در سررسید
کدام پایهها اعمال میشوند؟
کارمزد اعمال
سود/زیان
S < K1
هیچکدام
صفر
سود کامل = اعتبار خالص دریافتی
K1 < S < K2
فروش K1
کارمزد اعمال فروشنده روی K1
کاهنده تا حداکثر زیان
K2 < S < K3
فروش K1 + خرید 2×K2
کارمزد فروشندهٔ K1 + دو کارمزد خریدار K2
افزاینده از حداکثر زیان به بالا
S > K3
هر سه پایه
کارمزد فروشندهٔ K1 و K3 + دو کارمزد خریدار K2
سود ثابت = اعتبار − کارمزد اعمال
پس در فرمول باید کارمزد اعمال را تابعی از قیمت فرضی سررسید نوشت، نه یک عدد ثابت:
const exerciseFeeAt = (price, midOpt, highOpt) => {
if (!SETTING_FEE_EXERCISE) return 0;
let ex = 0;
if (price > option.strike) ex += option.strike * option.size * option.writeExerciseFee;
if (price > midOpt.strike) ex += 2 * midOpt.strike * option.size * midOpt.buyExerciseFee;
if (price > highOpt.strike) ex += highOpt.strike * option.size * highOpt.writeExerciseFee;
return ex;
};
const exZoneLow = SETTING_FEE_EXERCISE
? option.strike * option.size * option.writeExerciseFee : 0; // K1..K2
const exZoneMid = exerciseFeeAt(midOption.strike + 1, midOption, highOption); // K2..K3
const exZoneTop = exerciseFeeAt(highOption.strike + 1, midOption, highOption); // بالای K3
اشتباهی که ستون را غلط میکند
اگر برای سربهسر بالا از کارمزد ناحیهٔ «بالای K3» استفاده کنید، پایهٔ K3 را هم اعمالشده حساب کردهاید در حالی که سربهسر بالا زیر K3 است. همین جابهجایی ناحیه در سهام تا حدود نیم درصد قیمت پایه خطا میدهد — و همین اندازه فاصله معمولاً تمام سود این استراتژی است.
سود دو دنباله، حداکثر زیان و دو سربهسر
با تقارن اعمالها (K1 − 2K2 + K3 = 0) شکل بازده در سررسید ساده است: دو فلات سود در دو طرف و یک قلهٔ زیان روی K2.
دو فلات سود در دو طرف و یک قلهٔ زیان روی K2 — ولی بدترین نقطه ذرهای بالاتر از K2 است، جایی که دو پایهٔ خریداریشده با ارزش ذاتی صفر اعمال میشوند.کارمزد اعمال فروشندهٔ K3 یکجا اضافه میشود، پس ممکن است کمی زیر K3 در سود باشید و بالای آن در زیان — منحنی همانجا یک پله میپرد.
// سود دنبالهٔ پایین و بالا (جدا از هم)
const profitDown = netCreditCash; // زیر K1 هیچ اعمالی نیست
const profitUp = netCreditCash - exZoneTop; // بالای K3 هر سه پایه اعمال میشوند
const plBelowK3 = netCreditCash - exZoneMid; // درست زیر K3
// سود قابل اتکا در هر دو جهت خروج از محدوده
const maxProfit = Math.min(profitDown, profitUp);
// حداکثر زیان: درست بالای K2 (بدترین نقطه)
const gap1 = midOption.strike - option.strike;
const maxLoss = (gap1 * option.size) - netCreditCash + exZoneMid;
// دو سربهسر — هر ناحیه با کارمزد خودش
const lowerBE = option.strike + ((netCreditCash - exZoneLow) / option.size);
const upperBE = highOption.strike - (plBelowK3 / option.size);
حداکثر زیان دقیقاً روی K2 نیست، بلکه ذرهای بالاتر است: در همان نقطه دو پایهٔ خرید K2 هم اعمال میشوند در حالی که ارزش ذاتیشان صفر است، پس کارمزد خریدار هم اضافه میشود.
اگر plBelowK3 <= 0 باشد سربهسر بالا وجود ندارد: کارمزد اعمال K1 و دو پایهٔ K2 از اعتبار بیشتر شده و کل ناحیهٔ K2 تا K3 زیان است.
پرش نزولی روی K3: چون کارمزد اعمال فروشندهٔ K3 یکجا اضافه میشود، ممکن است کمی زیر K3 در سود باشید و بالای K3 در زیان. این تنها استراتژی باترفلای است که در بازار ایران این پرش را جدی نشان میدهد.
یک تابع P&L بنویسید و همهٔ اعداد نمایشی را با آن اعتبارسنجی کنید؛ اگر currentPnL(lowerBE) و currentPnL(upperBE) صفر نشدند، فرمول سربهسرها غلط است:
const currentPnL = (price) => {
let intrinsic = 0;
if (price > option.strike) intrinsic -= (price - option.strike); // Short K1
if (price > midOption.strike) intrinsic += 2 * (price - midOption.strike); // Long 2x K2
if (price > highOption.strike) intrinsic -= (price - highOption.strike); // Short K3
return (intrinsic * option.size) + netCreditCash - exerciseFeeAt(price, midOption, highOption);
};
حلقهٔ تو در تو و شرط تقارن
optionSE(n) برای n ≥ 0 قرارداد nام از اعمال ردیف جاری به بالا را میدهد (0 = خود ردیف)، مرتبشده بر اساس قیمت اعمال. پس دو حلقهٔ تو در تو خودبهخود K1 < K2 < K3 را تضمین میکنند:
حلقه با شرطِ بزرگتر بودنِ اندیس دوم، جفتها را میسازد و شرط تقارن غربالشان میکند: فاصلهٔ K1 تا K2 باید با K2 تا K3 برابر باشد.حلقه با شرطِ بزرگتر بودنِ اندیس دوم، جفتها را میسازد و شرط تقارن غربالشان میکند: فاصلهٔ K1 تا K2 باید با K2 تا K3 برابر باشد.
let indexMid = 0;
while (optionSE(++indexMid) !== undefined) {
const midOption = optionSE(indexMid); // K2
if (midOption.ti.sell1Volume < 2 || midOption.ti.sell1Price === 0) continue;
let indexHigh = indexMid;
while (optionSE(++indexHigh) !== undefined) {
const highOption = optionSE(indexHigh); // K3
if (highOption.ti.buy1Volume === 0 || highOption.ti.buy1Price === 0) continue;
// شرط تقارن باترفلای — ریاضی سربهسر بالا به آن تکیه دارد
const gap1 = midOption.strike - option.strike;
const gap2 = highOption.strike - midOption.strike;
if (gap1 !== gap2 || gap1 <= 0) continue;
// محاسبات…
}
}
شرط gap1 <= 0 همزمان اعمالهای تکراری را حذف میکند. اگر تقارن را بردارید دیگر باترفلای ندارید و فرمول سربهسر بالا معتبر نیست — آن حالت باترفلای بالشکسته است و ریاضی جداگانه دارد.
سرمایهٔ درگیر، وجه تضمین و pos.add
شورت کال باترفلای را میتوان «کال اسپرد نزولی (فروش K1 + خرید K2) + کال اسپرد صعودی (خرید K2 + فروش K3)» دید. این تفکیک، پاسخ وجه تضمین را میدهد:
پایهٔ فروش K3 با پایهٔ خرید K2 که اعمال پایینتری دارد کاملاً پوشش داده میشود ⇒ وجه تضمین ندارد.
پایهٔ فروش K1 اعمال پایینتر از پایهٔ خرید دارد ⇒ پوشش کامل نیست و «اختلاف دو اعمال منهای پرمیوم دریافتی» قفل میشود؛ اگر این عدد منفی شد یا از وجه تضمین استاندارد فروش بیشتر بود، وجه تضمین استاندارد ملاک است.
const k1DefaultMargin = option.requiredMargin || 0;
let k1Margin = (gap1 - bid1) * option.size;
let useDefaultMargin = false;
if (k1Margin <= 0) { k1Margin = k1DefaultMargin; useDefaultMargin = true; }
else if (k1DefaultMargin > 0 && k1Margin > k1DefaultMargin) { k1Margin = k1DefaultMargin; useDefaultMargin = true; }
const netCashOut = ((2 * ask2 - bid3) * option.size) + tradeFee;
const requiredCapital = Math.max(k1Margin + netCashOut, 1);
// همان عدد وجه تضمین را به نمودار هم بدهید تا سرمایهٔ ستون و نمودار یکی شود
pos.add('sell', option.namad, 1, 'buy', k1Margin > 1 ? k1Margin : true);
pos.add('buy', midOption.namad, 2, 'sell');
pos.add('sell', highOption.namad, 1, 'buy', false); // پوششداده با K2
return pos.build('شورت کال باترفلای ' + option.namad, SETTING_FEE, 'itm-only');
پارامتر پنجم pos.add عدد هم میپذیرد
در pos.add(side, namad, count, price, cashBlock) مقدار true یعنی «وجه تضمین استاندارد را خودت حساب کن»، false یعنی «پوششداده است و وجه تضمین ندارد»، و یک عدد یعنی «همین مقدار قفل میشود». اگر در ستون وجه تضمین اسپرد را لحاظ کردهاید ولی به نمودار false بدهید، سرمایهٔ ستون و نمودار با هم نمیخواند.
مشاهده وگا و سایر یونانیها در نمودار استراتژی
علاوه بر ستون و فیلتر دیدهبان، در نمودار استراتژی میتوانید یونانیها را روی منحنی سود/زیان ببینید: موقعیتهای call/put را اضافه کنید، از بخش «یونانیها» روی نمودار استفاده کنید و حساسیت کل استراتژی به قیمت پایه و زمان را لحظهای بررسی کنید. جمع دلتای موقعیتها در پایین جدول نیز نمایش داده میشود.
شورت باترفلای وگای مثبت دارد: با رشد نوسان ضمنی سود میکند و اگر قیمت روی بدنه بماند تتای منفی به آن ضرر میزند. برای مرور این دو ضریب: وگا و تتا.
سود تضمینی: وقتی اعتبار از فاصلهٔ اعمال بیشتر است
اگر اعتبار خالص دریافتی از (K2 − K1) × اندازه قرارداد بیشتر شود، maxLoss منفی میشود؛ یعنی موقعیت در هیچ قیمتی زیان نمیدهد. این ترکیبها را نباید با continue حذف کرد — همانها ارزشمندترین یافتهٔ اسکنر هستند:
وقتی اعتبار خالص از فاصلهٔ اعمال بیشتر شود، حتی قلهٔ زیان هم بالای صفر میماند — ولی چنین ردیفی معمولاً نقدشونده نیست.
const hasGuaranteedProfit = maxLoss <= 0;
const guaranteedProfit = hasGuaranteedProfit ? -maxLoss : 0;
// در این حالت سربهسر وجود ندارد، احتمال موفقیت ۱۰۰٪ و نسبت سود به زیان بینهایت است
در بازار کمعمق ایران بخشی از این موارد محصول سرخطهای قدیمی یا کمحجم است، نه قیمتگذاری اشتباه واقعی؛ بنابراین همیشه کنار آن فیلتر حداقل ارزش سفارش هر پایه را روشن نگه دارید (سنجش نقدشوندگی).
ثابتهای SETTING_ و FILTER_
برای اتصال خودکار به پنجرهٔ تنظیمات ویژوال (راهنمای تنظیمات ویژوال) از پیشوندهای استاندارد استفاده کنید:
const SETTING_COLLATERAL = true; // وثیقه/سرمایه درگیر در برابر وجه تضمین کامل دو پایهٔ فروش
const SETTING_FEE = true; // کارمزد معامله
const SETTING_FEE_EXERCISE = true; // کارمزد اعمال
const FILTER_MIN_RETURN = 1; // حداقل سود ماهانه (کمترین سود دو دنباله)
const FILTER_MIN_ORDER_VALUE = 10; // حداقل ارزش سفارش هر پایه (میلیون ریال)
const FILTER_MIN_K2_VOLUME = 1000; // حداقل حجم معاملات بدنه
const FILTER_PRICE_ZONES = '1,2,3,4,5';
const FILTER_REQUIRE_UPSIDE_PROFIT = false; // فقط سود در هر دو دنباله
const FILTER_GUARANTEED_ONLY = false; // فقط سود تضمینی
const FILTER_SHOW = false;
const FILTER_RESULT = false;
FILTER_REQUIRE_UPSIDE_PROFIT — فقط ترکیبهایی که بالای K3 هم پس از کارمزد اعمال سه پایه سود میدهند
FILTER_GUARANTEED_ONLY — فقط ترکیبهای بدون ناحیهٔ زیان
FILTER_PRICE_ZONES — پنج زون: زیر K1، K1 تا سربهسر پایین، بین دو سربهسر (زیان)، سربهسر بالا تا K3، بالای K3
FILTER_MIN_K2_VOLUME — بدنه دو قرارداد است و کمعمقترین پایه محسوب میشود
استراتژی آماده
اگر نمیخواهید از صفر بنویسید، استراتژی آمادهٔ شورت کال باترفلای در دیدهبان همین منطق را اجرا میکند: اسکن همهٔ ترکیبهای متقارن، سود دو دنباله، حداکثر زیان، دو سربهسر، احتمال موفقیت و نمودار. راهنمای گامبهگام: پیادهسازی شورت کال باترفلای در دیدهبان · فهرست همهٔ اسکنرها: استراتژیهای آماده.
جمعبندی: در فرمولنویسی این استراتژی سه چیز تعیینکننده است: سمت درست سرخط برای هر پایه، تفکیک کارمزد اعمال به سه ناحیهٔ سررسید (وگرنه سود دنبالهٔ بالا و هر دو سربهسر غلط میشوند)، و وجه تضمین پایهٔ فروش K1 که با پوشش K2 به «اختلاف دو اعمال» کاهش مییابد. اعداد نمایشی را همیشه با تابع currentPnL خودتان راستیآزمایی کنید.