ستونها و فیلترهای دیدهبان آپشنباز با جاوااسکریپت نوشته میشوند — همان زبانی که صفحههای وب با آن کار میکنند، نه یک زبان اختصاصیِ ساختهشده برای این سایت و نه فرمولنویسی سبک اکسل. این مقاله همان چند دستوری را که در فرمولهای واقعی دیدهبان به کار میروند توضیح میدهد: متغیر، ثابت، شرط، حلقه، آرایه، تابع و کار با متن و عدد. هدف این نیست که برنامهنویس شوید؛ هدف این است که وقتی یک فرمول آماده را باز میکنید بفهمید هر خطش چه میگوید و بتوانید تغییرش بدهید. فهرست فیلدها و توابع آماده در راهنمای فرمولنویسی داخل سایت است و اینجا تکرار نمیشود.
فرمولنویسی آپشنباز با چه زبانی نوشته میشود؟
زبان، جاوااسکریپت است. این یعنی هر چیزی که دربارهٔ جاوااسکریپت جای دیگری یاد گرفتهاید اینجا هم کار میکند، و هر سؤالی که در حین فرمولنویسی برایتان پیش میآید را میتوانید مستقیم در منابع عمومی جاوااسکریپت جستوجو کنید. آپشنباز چیزی به زبان اضافه نکرده؛ فقط چند آبجکت داده (قرارداد، نماد پایه) و دهها تابع آماده را داخل محیط اجرای فرمول شما قرار داده است.
فرمول شما هر بار که قیمتها بهروز میشوند اجرا میشود، و یک بار به ازای هر قرارداد جدول. یعنی وقتی یک زنجیره 40 قرارداد دارد، فرمول شما 40 بار اجرا میشود و هر بار متغیر option به یکی از آنها اشاره میکند.
یک فرمول دقیقاً چه شکلی است؟
یک فرمول میتواند به سه شکل نوشته شود، و تفاوتشان فقط سر return است.
یک) عبارت تکخطی. اگر کل فرمول یک عبارت باشد، لازم نیست return بنویسید؛ موتور خودش نتیجه را برمیگرداند:
دو) بدنهٔ چندخطی با return. بهمحض اینکه چند دستور پشت سر هم بنویسید، خودتان باید بگویید چه چیزی برگردد:
سه) بدنهٔ چندخطی بدون return — که کار نمیکند. این حالت خطا نمیدهد و دقیقاً به همین دلیل گیجکننده است. فرمول کامپایل میشود، سلول هم پر میشود، ولی چیزی که در آن میبینید یک هشدار است نه محاسبهٔ شما:
اگر یک ستون تازه ساختید و همهٔ سطرها یک هشدار نارنجی نشان دادند، اولین چیزی که باید چک کنید همین است: خط آخر return دارد؟
ستون یا فیلتر — یک زبان، دو نقش
ستون و فیلتر با همان زبان و همان فیلدها نوشته میشوند. تفاوت فقط در چیزی است که برمیگردانید:
یک ستون محاسباتی هرچه برگرداند در سلول چاپ میشود — عدد، متن، یا حتی متنِ رنگی که با تابع style() ساختهاید:
یک فیلتر فقط true یا false برمیگرداند. هر قراردادی که false بگیرد از جدول حذف میشود:
| ستون محاسباتی | فیلتر | |
|---|---|---|
| چه چیزی برمیگرداند | عدد یا متن (هرچه در سلول میخواهید) | فقط بله یا خیر |
| نتیجهاش کجا دیده میشود | یک ستون تازه در جدول | کم و زیاد شدن سطرهای جدول |
| وقتی داده ندارید | return '' تا سلول خالی بماند | return false تا سطر حذف شود |
ساختن هر دوی اینها قدمبهقدم در مقالهٔ ستون محاسباتی و راهنمای پنجرهٔ فرمولنویسی آمده است؛ اگر با کد راحت نیستید، رابط گرافیکی ساخت ستون و فیلتر همین کارها را بدون تایپ کد انجام میدهد.
داده از کجا میآید — آبجکتها در یک نگاه
قبل از اینکه سراغ دستورها برویم، باید بدانید دادهها کجا نشستهاند. موتور چند آبجکت آماده را داخل فرمول شما میگذارد و شما با نقطه به فیلدهایشان میرسید:
| آبجکت | چیست | نمونه فیلد |
|---|---|---|
option | خودِ قرارداد اختیار معاملهٔ همان سطر | option.strike · option.type · option.iv |
option.ti | تابلوی معاملاتی همان قرارداد | option.ti.lastPrice · option.ti.sell1Price |
ua | نماد پایه | ua.namad · ua.hv · ua.ivRank |
ua.ti | تابلوی معاملاتی نماد پایه | ua.ti.lastPrice · ua.ti.volume |
context | تنظیمات لحظهای دیدهبان، مثل مبنای قیمت | context.priceBase |
کنار این آبجکتها، دهها تابع آماده هم داخل فرمول در دسترساند — از breakeven() و calcBS() تا commaSeparator() و style(). فهرست کامل فیلدها و توابع با مثال، در راهنمای فرمولنویسی داخل سایت است؛ اگر فیلدی میخواهید که اصلاً وجود ندارد، میتوانید با فیلدهای شخصی خودتان بسازیدش. باقی این مقاله دربارهٔ فیلدها نیست — دربارهٔ دستورهایی است که با آنها کار میکنند.
متغیر و ثابت
متغیر یک جعبه است که یک مقدار را در آن میگذارید تا بعداً چند بار استفادهاش کنید. در جاوااسکریپت دو کلمه برای ساختنش هست: let و const.
let برای مقداری است که در جریان محاسبه عوض میشود، و const برای مقداری که تا آخر فرمول ثابت میماند. اگر بخواهید مقدار یک const را عوض کنید، فرمول خطا میدهد — و این دقیقاً کاری است که از آن انتظار دارید: عددی که قرار بود ثابت بماند، سهواً وسط محاسبه عوض نمیشود.
در عمل، let برای محاسبات میانی است و const برای تنظیمات فرمول. و اینجا یک قرارداد خانگی آپشنباز هست که خوب است بدانید: هر const که اسمش با FILTER_، SHOW_ یا SETTING_ شروع شود، بهطور خودکار در پنل تنظیمات همان فرمول یک گزینه میشود.
یعنی کسی که این فیلتر را نصب میکند، برای عوض کردن «حداکثر فاصله تا اعمال» لازم نیست کد را باز کند؛ عدد را از پنل تنظیمات عوض میکند. همهٔ جزئیات این پنل در راهنمای تنظیمات ویژوال آمده، و فرمولهای آمادهٔ دیدهبان همگی با همین قرارداد نوشته شدهاند.
نامهایی که نباید برای متغیر خودتان انتخاب کنید
option، ua، context، pos و positions از قبل توسط موتور پر شدهاند. اگر متغیری با همین نامها بسازید، از آن خط به بعد نام شما جای آبجکت اصلی را میگیرد و دسترسی به دادهها را از دست میدهید:
بدترین بخشش این است که هیچ خطایی نمیبینید: فرمول سالم اجرا میشود و سلول فقط خالی میماند، انگار دادهای وجود ندارد. یک پیشوند کوچک — مثلاً myOption — کل ماجرا را حل میکند.
عملگرها
عملگرها سه دستهاند: حسابی (که عدد میسازند)، مقایسهای (که بله/خیر میسازند) و منطقی (که بله/خیرها را به هم میبندند).
| عملگر | معنی | نمونه |
|---|---|---|
+ - * / | جمع، تفریق، ضرب، تقسیم | option.strike + option.ti.lastPrice |
% | باقیمانده تقسیم | days % 7 |
== | مساوی است؟ | option.type == 'call' |
!= | مساوی نیست؟ | option.state != 'OTM' |
> | بزرگتر است؟ | option.iv > 0.5 |
< | کوچکتر است؟ | option.daysUntilMaturity < 30 |
>= | بزرگتر یا مساوی | option.openInterest >= 100 |
<= | کوچکتر یا مساوی | gap <= 10 |
&& | و — هر دو شرط باید برقرار باشند | iv > 0.3 && iv < 0.8 |
|| | یا — یکی از دو شرط کافی است | state == 'ITM' || state == 'ATM' |
! | نه — جواب را وارونه میکند | !option.ti.lastPrice |
دو مساوی یا سه مساوی؟
== فقط مقدار را میسنجد و === علاوه بر مقدار، نوع را هم میسنجد. در بیشتر فرمولها هر دو یک جواب میدهند و فرقی نمیکند کدام را بنویسید — بهجز یک مورد که بدجوری گاز میگیرد.
در جاوااسکریپت 0 == '' برابر true است. فرمولهای آماده معمولاً با شرطِ «اگر این تنظیم خالی است، نادیدهاش بگیر» نوشته میشوند، و آن شرط با == سنجیده میشود. یعنی اگر در پنل تنظیمات عدد صفر بگذارید، فرمول فکر میکند تنظیم را خالی گذاشتهاید و آن فیلتر را کلاً خاموش میکند:
راهحل ساده است: هر جا منظورتان «فقط بالای صفر» است، عدد کوچکی مثل 0.1 بگذارید نه صفر. و اگر خودتان فرمول مینویسید، گاردِ خالیبودن را با !== '' بنویسید تا صفر از آن رد شود.
شرط — if، else و شرط کوتاه
شرط، پرکاربردترین دستور در کل کتابخانهٔ فرمولهای دیدهبان است — تقریباً هیچ فرمول واقعیای نیست که دستکم یک if نداشته باشد.
نردبان if / else if / else
شرطها از بالا به پایین سنجیده میشوند و اولین شرطی که درست باشد برنده است؛ بقیه اصلاً بررسی نمیشوند. پس ترتیب نوشتنشان معنی دارد — اگر در مثال زیر شرط iv > 0.3 را اول بنویسید، دیگر هیچوقت به «خیلی بالا» نمیرسید:
شرط کوتاه (ternary)
وقتی فقط دو حالت دارید، نوشتن چهار خط if و else زیادی است. علامت ? همان کار را در یک خط میکند: شرط، بعد ?، بعد جوابِ حالت درست، بعد :، بعد جوابِ حالت دیگر. چون یک عبارت است نه یک دستور، میشود مستقیم داخل یک محاسبهٔ دیگر گذاشتش — و میشود مثل نمونهٔ زیر زنجیرهاش کرد:
زنجیره کردن بیش از دو تا شرط کوتاه پشت سر هم خوانایی را از بین میبرد. از سه حالت به بالا یا نردبان if بنویسید یا switch:
الگوی «دروازهٔ محافظ» — return زودهنگام
این الگو در تقریباً همهٔ فرمولهای آمادهٔ دیدهبان تکرار شده و ارزش یاد گرفتن دارد. بهجای اینکه کل محاسبه را داخل یک if بزرگ بپیچید، همان اول کار هر حالتی را که نمیتوانید محاسبه کنید با یک return میبندید. آنچه باقی میماند، محاسبهای است که مطمئنید دادهاش سالم است:
در دیدهبان این محافظها تزئینی نیستند. خیلی از فیلدهای تابلو میتوانند صفر یا خالی باشند — قراردادی که امروز اصلاً معامله نشده، نمادی که دامنهٔ نوسان ندارد، سرخط عرضهای که خالی است. بدون دروازه، همان صفرها به تقسیم بر صفر و عددهای بیمعنی در جدول تبدیل میشوند.
آرایه و حلقه
آرایه — تکههای خروجی را کنار هم بچینید
آرایه یک فهرست است. رایجترین کاربردش در ستونها این است که هر تکهٔ خروجی را با push به فهرست اضافه کنید و آخر کار با join همه را به یک متن تبدیل کنید. مزیتش نسبت به چسباندن مستقیم متنها این است که هر تکه را میتوانید با یک if جداگانه روشن و خاموش کنید:
حلقه — یک کار روی همهٔ قراردادها
تا اینجا هر فرمول فقط با قرارداد همان سطر کار داشت. گاهی به همهٔ قراردادهای زنجیره نیاز دارید — مثلاً برای جمع کل موقعیت باز، یا برای ستون max pain که باید به ازای هر قیمت اعمال، زیان کل را حساب کند. اینجاست که حلقه لازم میشود:
سه بخش داخل پرانتز for به ترتیب یعنی: از کجا شروع کن، تا کِی ادامه بده، و هر بار چقدر جلو برو. متغیر totalOI عمداً بیرون از حلقه تعریف شده، چون قرار است بعد از تمام شدن حلقه هم باقی بماند.
اگر با حلقه راحت نیستید، جاوااسکریپت راه کوتاهتری هم دارد. filter فهرست را غربال میکند، forEach روی همهٔ اعضا یک کار را تکرار میکند و map هر عضو را به چیز دیگری تبدیل میکند:
و sort فهرست را مرتب میکند. برای مرتب کردن عددها حتماً باید تابع مقایسه بدهید، وگرنه جاوااسکریپت اعداد را مثل متن مرتب میکند و 100 قبل از 20 میآید:
حلقه روی زنجیره را ارزان حساب نکنید
فرمول شما به ازای هر قرارداد یک بار اجرا میشود. اگر داخل آن یک حلقه روی کل زنجیره بگذارید، تعداد محاسبات ضرب میشود — یک زنجیرهٔ 40 قراردادی میشود 1,600 بار. برای یک زنجیره اهمیتی ندارد، ولی وقتی چند نماد را همزمان در دیدهبان باز کردهاید، همین ستون میتواند جدول را کند کند. اگر حلقه لازم است، اول با یک شرط سبک قراردادهای بیربط را کنار بگذارید.
تابع
تابع یک تکه محاسبه است که اسم دارد و میتوانید هر جا لازم شد صدایش بزنید. داخل همان فرمول تعریفش میکنید و بلافاصله استفادهاش میکنید:
چیزی که داخل پرانتز میگیرد ورودی است و چیزی که با return پس میدهد خروجی. در نمونهٔ بالا priceOf یک قرارداد میگیرد و قیمتش را میدهد؛ چون ورودی میگیرد، همان تابع را میشود روی قرارداد سطر و روی قرارداد مقابلش هم اجرا کرد بدون اینکه کد را دو بار بنویسید.
تابع عمومی — یک بار بنویس، در چند فرمول استفاده کن
اگر یک محاسبه را در چند ستون و فیلتر لازم دارید، آپشنباز یک نوع ذخیرهٔ سوم دارد: تابع. آیتمی که با این نوع ذخیره شود در جدول ستون نمیسازد؛ موتور آن را قبل از اجرای همهٔ ستونها و فیلترها بارگذاری میکند تا بقیه بتوانند صدایش بزنند.
و بعد در یک ستون:
و در یک فیلتر، با همان تابع:
سودش فقط کمتر تایپ کردن نیست. اگر روزی تعریف «ارزانی نسبت به قیمت تئوری» را عوض کنید، یک جا عوضش میکنید و هر سه فرمول با هم بهروز میشوند. محاسبهای که در دو فرمول کپی شده باشد، دیر یا زود یکیاش اصلاح میشود و دیگری نه.
کار با متن و عدد
ساختن متن سلول
متنها را میشود با + به هم چسباند، ولی وقتی چند تکه شد خواندنش سخت میشود. راه تمیزتر، رشتهٔ قالببندیشده است: متن را بین دو بکتیک میگذارید و هر جا مقدار محاسباتی میخواهید، آن را داخل ${...} مینویسید:
گرد کردن و قالب عدد
Math توابع ریاضی استاندارد جاوااسکریپت را دارد و همهشان در فرمول در دسترساند:
| تابع | چه میکند |
|---|---|
Math.abs(x) | قدر مطلق — علامت منفی را برمیدارد |
Math.round(x) | گرد کردن به نزدیکترین عدد صحیح |
Math.floor(x) | گرد کردن به پایین |
Math.ceil(x) | گرد کردن به بالا |
Math.max(a, b) | بزرگترین مقدار |
Math.min(a, b) | کوچکترین مقدار |
Math.sqrt(x) | جذر |
Math.pow(x, y) | توان |
برای نمایش عدد در سلول، دو تابع خودِ آپشنباز معمولاً بهتر از ابزار استاندارد جاوااسکریپت جواب میدهند: roundNumber(x, n) که برخلاف toFixed خروجی عدد میدهد نه متن، و commaSeparator(x) که جداکنندهٔ هزارگان میگذارد.
مقیاسها را قاطی نکنید
option.iv، option.wiv و ua.hv اعشاریاند — 0.42 یعنی 42 درصد. ولی ua.ivRank و ua.ivPercentile روی مقیاس 0 تا 100 هستند. قاطی کردن این دو، خطای صد برابری میسازد که هیچ پیام خطایی هم ندارد — عدد فقط غلط است. توضیح این دو مفهوم در مقالهٔ نوسان ضمنی و تاریخی است.
وقتی داده اصلاً وجود ندارد
خیلی از فیلدهای تابلو میتوانند خالی باشند — قراردادی که دیروز معامله نشده lastDayVolume ندارد، نمادی که صف است سرخط مقابل ندارد. سه ابزار برای این حالت هست:
!x برای «مقدار ندارد یا صفر است»؛ کوتاهترین گارد و همانی که در فرمولهای آماده بیشتر از همه دیده میشود. x == null فقط null و undefined را میگیرد و صفر را نمیگیرد — دقیقاً همان چیزی که برای فیلدی مثل «روز معاملاتی باقیمانده» لازم دارید، چون صفر آنجا یک مقدار معتبر است نه دادهٔ گمشده:
و ?? که یعنی «اگر خالی بود، این را بگذار». برای وقتی مناسب است که میخواهید محاسبه ادامه پیدا کند نه اینکه متوقف شود:
کامنت، و کاری که فقط در آپشنباز میکند
هر چیزی که بعد از // بیاید تا آخر آن خط، کامنت است و اجرا نمیشود. برای چند خط، متن را بین /* و */ میگذارید. کامنت در هر زبانی برای یادداشت است، ولی در آپشنباز یک کار دوم هم میکند:
کامنتِ کنار یک const که اسمش با FILTER_، SHOW_ یا SETTING_ شروع شود، برچسب همان گزینه در پنل تنظیمات میشود. سه چیز از آن خوانده میشود: متن اول برچسب است، هرچه بعد از title= بیاید تولتیپ راهنما میشود، و step= تعیین میکند دکمههای بالا و پایین عدد را چقدر جابهجا کنند. اگر مقدار بهجای عدد یکی از چند گزینهٔ ثابت باشد، گزینهها را داخل کروشه مینویسید.
یعنی وقتی برای فرمول خودتان کامنت مینویسید، در واقع دارید رابط کاربریاش را هم میسازید — و کسی که آن را نصب میکند بدون باز کردن کد میتواند تنظیمش کند. قواعد کامل این پنل در راهنمای تنظیمات ویژوال فرمول آمده است.
شش اشتباه رایج
| اشتباه | چه میبینید | درستش |
|---|---|---|
بدنهٔ چندخطی بدون return | همهٔ سلولها یک هشدار نارنجی | خط آخر را با return شروع کنید |
| گذاشتن عدد صفر در یک تنظیم فیلتر | فیلتر انگار اصلاً اعمال نمیشود | 0.1 بگذارید، نه 0 |
| نامگذاری متغیر با نامهای رزرو | خطای عجیب روی فیلدی که مطمئنید وجود دارد | myOption بهجای option |
| محاسبه بدون گارد روی فیلد خالی | NaN، Infinity یا عددهای پرت در جدول | اول دروازههای محافظ، بعد محاسبه |
استفاده از !x برای فیلدی که صفرش معتبر است | قراردادهای سررسید امروز بیصدا حذف میشوند | x == null بنویسید |
| قاطی کردن مقیاس اعشاری و صددرصدی | عددی که صد برابر کوچک یا بزرگ است | iv اعشاری، ivRank از 100 |
از اینجا به بعد
حالا که زبان را میشناسید، سریعترین راه یاد گرفتن این است که فرمولهای موجود را باز کنید و بخوانید. سه مسیر پیشنهادی:
یک) از یک فرمول آماده شروع کنید. در تب «آماده» چند ستون و فیلتر نصبشدنی هست که هرکدام همان الگوهای این مقاله را دارند. یکی را نصب کنید، بازش کنید و خطبهخط بخوانید — فهرست کاملشان با توضیح هر تنظیم در فرمولهای آمادهٔ دیدهبان است.
دو) نمونههای آمادهٔ کد را بخوانید. نمونه کدهای کاربردی ستون و نمونه کدهای فیلترنویسی دهها فرمول کوتاه دارند که میتوانید مستقیم کپی کنید و تغییر بدهید.
سه) کار را به یک هوش مصنوعی بسپارید. اگر میدانید چه میخواهید ولی نمیدانید چطور بنویسیدش، پرامپت آمادهٔ فرمولنویسی کل مرجع موتور را در قالب یک متن قابلکپی دارد: آن را به ChatGPT یا Claude بدهید و بعد خواستهتان را توصیف کنید. با دانستن همین دستورها میتوانید نتیجهاش را بخوانید، بسنجید و اصلاحش کنید — که دقیقاً همان چیزی است که یک نسخهٔ اولِ تولیدشده لازم دارد.
و اگر کارتان با یک قرارداد تمام نمیشود و میخواهید روی یک موقعیت چندپایه فرمول بنویسید، همین زبان در ستون محاسباتی نمودار استراتژی هم کار میکند؛ فقط آبجکتهایش فرق دارند.
جمعبندی
زبان فرمولنویسی آپشنباز جاوااسکریپت است و برای استفاده از آن لازم نیست برنامهنویس باشید. عملاً با چند دستور میشود بیشتر کارها را کرد: متغیر برای نگه داشتن مقدار، if و شرط کوتاه برای تصمیمگیری، آرایه برای چیدن خروجی، حلقه برای وقتی که به کل زنجیره نیاز دارید، و تابع برای اینکه یک محاسبه را دو بار ننویسید. مهمترین چیزی که از این مقاله باید همراهتان بماند سهتاست: بدنهٔ چندخطی return میخواهد، فیلتر فقط بله/خیر برمیگرداند، و قبل از هر محاسبهای باید مطمئن شوید دادهاش خالی نیست.
بهترین جای تمرین، خود دیدهبان است: یک ستون آماده نصب کنید، کدش را باز کنید و یک عدد را عوض کنید تا ببینید جدول چطور تغییر میکند. دیدهبان آپشن را باز کنید (راهنمای دیدهبان) و از دکمهٔ «فرمول نویسی» شروع کنید.