eSKon2 написал: Подскажите, где взять список актуальных имён параметров для вызова getParamEx?
Прошу прощения, параметры инструментов здесь: Руководство пользователя Quik / Раздел 8. Алгоритмический язык QPILE / Функции для получения значений Таблицы текущих торгов / Значения параметров функций. Но первая ссылка тоже пригодится.
eSKon2 написал: Подскажите, где взять список актуальных имён параметров для вызова getParamEx?
Руководство пользователя Quik / Раздел 6. Совместная работа с другими приложениями / Импорт транзакций / Формат .tri-файла с параметрами транзакций.
Просто контора решила, что дублировать эту информацию в справку по QLua совсем не обязательно. Хорошо это или плохо - этому вопросу тут можно посвятить не один десяток постов.
Юлия написал: что к моменту вызова getFuturesHolding информация в этой таблице еще не обновилась после сделки
Именно так. OnTrade, как правило, - самый "быстрый" коллбэк из всех событий, относящихся к торговым действиям. Quik весь устроен так, что информация в разные таблицы приходит независимыми потоками, никак не синхронизированными друг с другом. Это много раз здесь обсуждалось. Поэтому совокупное состояние таблиц терминала в любой момент времени ("срез данных") никак нельзя считать согласованным. Другое дело, что когда мы смотрим в таблицы глазами, относительные задержки обновления информации так малы, что мы их не замечаем. И которые нельзя не учитывать при программировании в скриптах.
Цитата
Юлия написал: Где тогда отлавливать момент совершения сделки
Придется вести позиции в собственных переменных скрипта самостоятельно, обновляя их в тех же OnTrade. Периодически, в периоды относительной "тишины" в торговле, синхронизируя значения с таблицей позиций Quik.
Цитата
Egor Zaytsev написал: Сама позиция в таблице меняется в QUIK?
Конечно она поменяется, куда денется. Тут и код выкладывать не нужно. Человек ведь пишет, что это происходит после вызова OnTrade.
Да, чтобы работали колбэки, совсем не обязательно определять эти функции в lua-скрипте. И даже использовать Trans2Quik. Функции колбэков можно регистрировать в глобальном окружении (_G) луа-машины из C-кода своей подключенной через 'require ...' DLL, тогда Quik обнаружит их и сможет вызывать.
Это сделать принципиально невозможно, так как мы не можем знать, следующий тик будет относиться к последней свече или уже к новой. Для решения этой проблемы можно использовать два подхода: 1. Рассчитывать индикатор только до предыдущей свечи, ибо тут мы точно знаем, что она завершена. В помощь функция SetValue(), позволяющая задать значение любой свечи, в том числе n-1. Подходит, если необязательно знать значение индикатора для последней свечи.
2. Если надо, чтобы индикатор работал "динамически", т.е. обновлялся на последней свече вместе с ней самой, используется специальная техника, которая заключается в сохранении каждый раз "внутреннего состояния" индикатора - набора переменных. Это позволяет последнюю изменяющуюся свечу каждый раз рассчитывать как будто новую.
Уверен, что проблема обнаружится намного быстрее, если вместо перечисления версий используемых инструментов выложите сюда нам посмотреть ваш простейший скрипт (но только файл целиком), который "не запускается".
Есть более гуманный способ. Вот небольшой технологический дайджест по теме:
1. qlua.dll - реализация lua5.1.dll специально для Квика с целью добавления потокобезопасных методов работы с таблицами из разных потоков (sinsert(), sremove() и т.п. - см. документацию по QLua). В остальном это полноценная Lua, с которой можно линковать и свои модули. 2. Чтобы всё работало, процесс вне зависимости от числа созданных в нем потоков должен загрузить только один экземпляр qlua.dll. Почему? В DLL помимо кода (количество экземпляров которого безразлично) есть еще и глобальные переменные, в числе которых необходимые примитивы синхронизации. Если они будут созданы в нескольких экземплярах, толку от них никакого и все труды по обеспечению потокобезопасности - впустую. 3. Так как сторонние библиотеки едва что-нибудь слыхивали про Квик про QLua в нем, то слинкованы они с lua5.1.dll или нечто подобным. Чтобы такие модули работали со скриптами в Квике, в комплекте программы поставляется lua5.1.dll - модуль-прокси, который полезного кода не содержит, но перенаправляет все вызовы API к qlua.dll, таким образом решая две задачи: 1) внешние модули, слинкованные с lua5.1.dll, успешно его находят и загружают; 2) обеспечивается загрузка только одного экземпляра API Lua, а именно qlua.dll.
Выводы, для того чтобы всё находилось, загружалось и не падал терминал: 1. Из папок с файлами сторонних модулей можно удалить все lua5.1.dll, чтобы гарантированно обеспечить загрузку lua5.1.dll именно из папки Квика, то есть нашу заботливо изготовленную прокси. 2. Если внешние модули слинкованы не с lua5.1.dll, а с lua51.dll, lua.dll или подобным, скопируйте прокси lua5.1.dll из поставки Квика (!) в ту же его папку и обзовите файл как надо. Внимание, еще раз: qlua.dll копировать нельзя, прокси lua5.1.dll - можно! А еще лучше не копировать, а создать символическую ссылку (symlink) на lua5.1.dll, если у вас файловая система NTFS. Это избавит от лишних хлопот, если внезапно lua5.1.dll обновится вместе в Квиком. 3. Кто использует LuaSSL, библиотеки libeay32.dll и ssleay32.dll кладите в папку Квика, так как LuaSSL сделан так, чтобы эти библиотеки и lua5.1.dll находились в одном месте.
Atom написал: Благодарю за ответ, но все равно не могу понять, почему считает так, ну и что что счет с нуля если index-1 по идее значения предыдущей свечи должны быть, а не текущей
Представим себе, что сейчас в массиве ровно 10 свечей. Нумерация для значения index в OnCalculate и функциях O, H, L, C, V, T - от 1 до 10. Для функции getCandlesByIndex - от 0 до 9. Если в OnCalculate пришел index = 10, то получить Close последней свечи - C(10), либо её же - getCandlesByIndex(..., first_candle = 9, count = 1). Таким образом, для O, H, L, C, V, T используем index, для getCandlesByIndex() значение (index - 1).
"TABLE t, NUMBER n, STRING l getCandlesByIndex (STRING tag, NUMBER line, NUMBER first_candle, NUMBER count) ... first_candle – индекс первой свечки. Первая (самая левая) свечка имеет индекс 0"
В индикаторах доступны функции O, H, L, C, V, T, в которых индекс соответствует получаемому в OnCalculate.
Вот вам пример функции для простейшего индикатора из одной линии, где можно убедиться в корректной работе:
Код
function OnCalculate(index)
return C(index)
end
Запустите и увидите, что значения индикатора для каждой свечи - просто её цены Close. А для последней, которая меняется, значение индикатора будет "прыгать" в соответствии с меняющейся (Close) ценой.
Насколько видно из описания проблемы, речь в данном случае идет об индикаторах, а именно об использовании там данных массива свечей. И еще можно догадываться, что вопросы к параметру index, приходящему в функцию OnCalculate. Если всё это так, то смысл термина "текущая свеча" здесь очень неопределен. Потому что, по замыслу OnCalculate, она вызывается для той свечи, для которой терминал хочет получить от вас рассчитанное значение индикатора. Единственное, что можно здесь надежно утверждать, что значения index, последовательно передаваемые в функцию, будут неубывающими. То есть возрастающими или, в крайнем случае, равными предыдущему значению. Далее, можно перейти к вопросу, когда же вызывается OnCalculate. Она вызывается либо когда вообще нет рассчитанных значений индикатора (в таком случае index последовательно пробежит от 1 до последнего номера из массива), либо когда какая-то свеча изменилась. Понятно, что при корректной работе системы поставки данных измениться может лишь последняя (пускай "текущая" в иной терминологии) свеча. Тогда OnCalculate её индекс и получит. Так что приведенная вами информация представляется мало правдоподобной. Ищите ошибку либо, возможно, нечетко сформулирована проблема. Что же касается индекса, с нуля он начинается или с единицы, то в данном случае это совершенно не имеет значения, поскольку вы далее обращаетесь за данными свечи ровно по тому индексу, которым вам пришел.
Целые числа в формате Lua "number" (он же C "double"), равно как и результаты операций +/- с ними, согласно особенностям IEEE 754, представляются точно. Поэтому просто не надо допускать невязок округления, и с целыми числами можно работать спокойно. А если невязки неизбежны, делать round().
Строки сравниваются в лексикографическом порядке, т.е. посимвольно слева направо. Так как "0" < "1" < ... < "9", то при использовании строкового формата даты "YYYYMMDD" сравнение будет корректным. Вывод: в данном случае использование как числового, так и символьного представления будет работать одинаково правильно. Такая теория интересовала?
Насколько нам (пользователям) известно из ранних обсуждений на данном форуме, при подаче из терминала рыночной (["TYPE"] = "M") заявки на FORTS сервер QUIK должен автоматически посылать в шлюз эту заявку с одной из цен PRICEMIN/PRICEMAX текущей сессии соответственно. Или это всё-таки не так?
1. почему не сортирует вообще никак, ни по ключу, ни по значению, хотя то и другое - натуральные числа?
Чтобы table.sort работала, нужно чтобы ключи были в терминологии Lua "массивом" (array), то есть являлись: 1. Положительными целыми числами. 2. Начинались с 1. 3. Не имели пропусков (максимальный индекс равен общему количеству элементов).
Что касается своих правил сортировки, table.sort предоставляет возможность задать вторым аргументом функцию, где эти собственные правила можно и реализовать. Подробности в документации на Lua.
Сергей написал: Данные два варианта точно эквивалентны? Я всерьез, т.к. не проф. программер и биты не люблю :)
Точно эквивалентны. С точки зрения логики это одно и то же условие.
По поводу флагов. Коллеги, поймите простую вещь, кто еще не понял. Биты 0 и 1 в trade.flags анализировать бессмысленно, так как они не отражают текущий статус соответствующей заявки. Для сделок они невалидны и могут иметь любые случайные значения.
bit.band(order.flags,1) == 0 and bit.band(order.flags,2) == 0
"Снята":
Код
bit.band(order.flags,1) == 0 and bit.band(order.flags,2) > 0
Не надо трогать OnTrade() и trade.flags, они тут совершенно ни при чем. Можете, конечно, контролировать исполнение подсчетом количества в сделках по заявке, но это будет другой способ.
Цитата
Сергей написал: Какой гарантирует, что заявка была на 100% filled?
Статус "Исполнена" - заявка была на 100% filled, можно не сомневаться.
Цитата
Сергей написал: что первый и второй биты касаются именно ЗАЯВКИ. Собственно, по-другому их и интерпретировать нельзя. Что значит применительно к сделке "снята" и как сделка может не быть исполнена
Применять к сделкам эти биты никак нельзя. Документация и здравый смысл правы. Смотреть на них в OnTrade() просто не надо. Совсем.
Логика говорит, что trade_num должны быть разными, даже когда сделки порождаются одной заявкой
Это не просто логика, а факт. "Сделка" как торговая единица и информационная сущность системы имеет уникальный номер, по крайней мере в пределах своего класса торгуемых инструментов. Количество в заявке N = n1 + n2 + ... nk, где n1, n2, ..., nk - количества в k сделках, которыми разобрана заявка. У всех 1..k сделок номера непременно разные.
судя по всему, у первой пришедшей trade_num был больше
А вот это легко. Хотя более поздние сделки при регистрации имеют бОльшие номера, мы точно не знаем, как устроены потоки данных от биржи до терминала (и скрипта). Поэтому предложенный мной вариант более надежен, мне пока непонятно, почему вы его назвали некорректным. Пока всё говорит о том, что как раз наоборот.
1. что есть такого критичного и необходимого в OnTransReply(), чего нельзя поймать через OnOrder() и OnTrade()?
В принципе, ничего. Для новых заявок позволяет связать trans_id с order_num. Для снятых полезная информация - неисполненный остаток (balance). Можно обойтись без него, но есть одно преимущество. OnTransReply(), как правило, приходит первым из всех событий, связанных с транзакцией. Для алгоритмов, критичных к быстродействию, позволяет сделать код более "интерактивным", т.е. быстрее реагирующим на происходящее.
Сергей написал: как отличать повторный вызов OnTrade() от вызова с тем же объемом (и всем остальным ?)
Разумеется, одна заявка с объемом >1 может исполняться несколькими разными сделками. А у разных сделок номера (trade_num) тоже разные (во всяком случае в пределах одного класса инструментов). Предложенное решение позволяет отфильтровывать именно дубликаты одной сделки, т.е. имеющие одинаковые номера trade_num.
Цитата
Сергей написал: Как узнать, это просто дубль пришел или моя заявка последовательно разбирается частями?
function OnTrade(trade)
if Trades[trade.trade_num] then return end -- Это дубль, ничего не делать
Trades[trade.trade_num] = os.time() -- Запомним время, понадобится для последующей очистки
<здесь ваш полезный код>
end
... ну и надо периодически прибираться, а то память кончится:
Код
function OnCleanUp()
for tradeNum, tradeDT in pairs(Trades) do
if os.time() - tradeDT >= 86400 then Trades[tradeNum] = nil end
end
<...>
end
Обратите внимание на их давность. Так что вместе с пониманием ограниченности ваших ресурсов прошу скорректировать управление процессом доработок продукта.
Версии 7.24-7.25, срочный рынок. При снятии заявки приходит, как положено, OnTransReply() с result_msg = "Заявка ... снята. Неисполненный остаток: 4". Лезем в поле balance и... balance = 0.04 (!) Самое интересное, до версии 7.24 всё было хорошо, а потом кому-то вдруг захотелось делить остаток на 100. Можно, конечно, обвешать любые данные, получаемые от терминала, всевозможными мыслимыми и немыслимыми проверками, но мы не хотим превращаться в параноиков. Всё-таки должны быть документированные договорённости, какие значения в каких пределах каких элементов данных мы можем ожидать от системы. Я надеюсь, что меня услышат и примут меры для усовершенствования процедур тестирования очередных релизов программы.
sav 312 написал: Спасибо, но тут дело принципа уже)) Как мое время "10:00:50" в этот формат перевести.
Пожалуйста:
Код
-- Текущие дата/время в виде таблицы:
dt_table = os.date("*t", os.time())
-- Теперь ставим время какое хотим:
dt_table.hour = 10
dt_table.min = 0
dt_table.hour = 50
-- ...и обратно в число:
my_time = os.time(dt_table)
Да, это является самым корректным способом при сравнении отметок времени. Всё зависит от конкретных условий, можно использовать упрощенный подход или нет. Вот, например, на срочном рынке в текущую сессию включаются сделки за вчерашнюю вечернюю сессию, т.е. перед сделкой сегодня за 10:00:00 в ТВС будет читаться запись за вчера за 23:49:59. Смотрите сами, чтобы не было некорректной работы вашего алгоритма.
sav 312 написал: Давайте попробуем иначе. Вот кусочек кода:
Код
time_sdelki = os.time (t.datetime)
Путем умножения, как вы предлагали часов на 3600 + минут на 60 + секунды мы не придем к формату time_sdelki. Сергей, Вы профи, а я начинающий поэтому могу не уловить с полуслова.
sav 312, Ваш расчет time_sdelki - это путь воина, который Вы сами себе избрали. Можно делать и так, но кто мешает сделать немного по-другому:
Если нет входящих (или текущих) позиций - таблица пустая - пишет ошибку. После совершения сделки считывается нормально. Скрипт невозможно запустить пока не совершишь сделку.
Каким образом можно обойти эту неприятность?
Да очень просто. Если строчки по инструменту в таблице вообще нет, то позиция, очевидно, равна 0. Позволю себе кое-что добавить в приведенный выше код:
Код
T_FuturesHolding = getFuturesHolding(Settings.FIRM_ID,Settings.ACCOUNT,Settings.SECCODE, 0)
if T_FuturesHolding then
totalnet = T_FuturesHolding.totalnet
esle
totalnet = 0 -- Если строчки нет
end
Масштаб проблемы намного больше. При установке опции "Исходя из настроек открытых пользователем таблиц" и при наличии во всех открытых таблицах терминала всего 2-х фьючерсов FORTS в диалоге выбора параметров, согласно сводке "Общая информация", у меня оказываются выбранными: - 17 классов из 27 доступных, - 10226 (!) инструментов из 11624, - 62 из 124 параметров.
При этом выбраны такие классы как Опционы, МБ ФР Облигации, Паи - этих инструментов вообще нет и в помине не было в таблицах. Для проверки терминал запускался "чистым" - с удаленными всеми *.dat, *.log, *.wnd. Результат совершенно аналогичный. Понятно, что для различных расчетов и механизмов контроля терминалу нужны определенные параметры некоторых инструментов, даже если их нет в открытых таблицах - например, ГО или курсы валют. Но такой номенклатуры и в таком масштабе это просто немыслимо! Я боюсь спросить - они все действительно заказаны и поступают с сервера? Не удивляюсь, что многие жалуются на производительность и нехватку ресурсов. В общем, просьба вернуться к этой проблеме. Либо предоставить здесь разъяснения о необходимости КАЖДОГО из 62 параметров КАЖДОГО из 10226 заказанных инструментов.
Борис Гудылин написал: В списке функций взаимодействия скрипта LUA и Рабочего места QUIK она именуется по другому ) CulcBuySell - функция для расчета максимально возможного количества лотов в заявке
Опечатка на странице со списком функций. На странице с описанием CalcBuySell всё правильно.
Для срочного рынка такой функции нет, вернее в самом QUIK такой информации нет.
Почему же нет? А это что:
CalcBuySell Функция предназначена для расчета максимально возможного количества лотов в заявке. Формат вызова: NUMBER qty, NUMBER comission CalcBuySell(STRING class_code, STRING sec_code, STRING client_code, STRING account, NUMBER price, BOOLEAN is_buy, BOOLEAN is_market)
VDV написал: Ограничения, на использование в индикаторах, в документации не упоминаются.
Упоминаются: Индикаторы технического анализа / Функции и глобальные переменные скрипта индикатора / Список функций, доступных из скрипта индикатора.
Увы, программно управлять параметрами индикатора в текущей реализации не получится, сколько там таблиц ни создавай. Вообще, почему нельзя создавать таблицы: скрипт индикатора неинтерактивен, его задача - рассчитывать значения и возвращать Квику, который этот индикатор сам будет рисовать. Это как, например, есть у вас функция для расчета синуса, ее кто-то вызвал с аргументом числовым некоторым и ожидает, что вы вернете синус этого числа. А вы вместо этого в коде функции открываете медиаплеер и начинаете ему проигрывать ролик с * кандидатов в президенты.
Однако решение есть, технология примерно такая. Если вам нужны значения индикатора с возможностью его пересчета с разными параметрами, необязательно обращаться к индикатору на графике, вполне можно рассчитывать его отдельно для себя в своем основном скрипте: 1) Пишете самостоятельную функцию расчета значений индикатора, выносите ее в отдельный файл. Функцию будете вызывать как из OnCalculate в индикаторе, так и из своего скрипта. 2) Создаете у себя таблицу-массив для хранения значений индикатора. 3) В цикле единовременно рассчитываете индикатор для существующих в терминале свечек. 4) Подписываетесь на изменение массива свечек SetUpdateCallback() или отслеживаете это любым другим удобным вам способом. 5) При появлении каждой новой свечки вызываете для нее вашу функцию расчета индикатора.
Таким способом вы получаете возможность самостоятельно полностью управлять расчетом любых нужных вам индикаторов независимо от навешанных на графики или даже отсутствия таковых, в том числе целиком пересчитывать их в любой момент с любыми параметрами.
Ушла ли заявка на биржу?, Заявка, выставляемая по стоп-заявке N [121500004], отвергнута торговой системой: Could not cancel order. [GW][14] "Не найдена заявка для удаления".
Поправка - "Снята" в случае исполненной связанной и выкинуть лимитную при наступлении условия после снятой связанной. "Отвергнута ТС" или иные причины можно писать только по результатам неудачного выставления новой заявки, а не снятия связанной.
Ушла ли заявка на биржу?, Заявка, выставляемая по стоп-заявке N [121500004], отвергнута торговой системой: Could not cancel order. [GW][14] "Не найдена заявка для удаления".
Понятно. Судя по всему, ее снял сам Квик при наступлении условия и в процессе исполнения стопа. Но ответ от шлюза не пришел в связи с возможными проблемами связи и он повторил попытку 6 раз, судя по вашему сообщению. Естественно, повторные попытки заканчивались ошибками, которые в конце концов дошли Квику от биржи. В любом случае состояние стопа должно в результате оказаться "Снята", а не "Исполнена" с результатом "Отвергнута ТС".
Ушла ли заявка на биржу?, Заявка, выставляемая по стоп-заявке N [121500004], отвергнута торговой системой: Could not cancel order. [GW][14] "Не найдена заявка для удаления".
Это SiZ7, верно? Исполниться связанная в 10:06-10:08 не могла, так как максимум был 59418. Можно выложить такую же полную табличку по лимитной 28763251083 и сделкам по ней (если были)?
Ушла ли заявка на биржу?, Заявка, выставляемая по стоп-заявке N [121500004], отвергнута торговой системой: Could not cancel order. [GW][14] "Не найдена заявка для удаления".
Ушла ли заявка на биржу?, Заявка, выставляемая по стоп-заявке N [121500004], отвергнута торговой системой: Could not cancel order. [GW][14] "Не найдена заявка для удаления".
Речь не о промежутке времени между выставлением и исполнением, а о совпадении по времени исполнения связанной и выполнения условия стопа. Выложите все параметры вашей заявки № 121500004 для более предметного разговора.
Ушла ли заявка на биржу?, Заявка, выставляемая по стоп-заявке N [121500004], отвергнута торговой системой: Could not cancel order. [GW][14] "Не найдена заявка для удаления".
Могу предположить причину подобной ситуации. В целом, стопы со связанной работают корректно, но в этом случае, видимо, исполнение связанной и условие стопа произошли практически одновременно. Квик, еще не поняв, что связанная исполнилась, попытался ее удалить, что привело к полученному результату. Получив ошибку, он не стал выставлять на биржу стоповый лимит и успокоился. Вот только заполнение в такой ситуации поля Результат = "Отвергнута ТС" является ошибкой и подлежит исправлению. Стоп-заявка при исполнении связанной (в том числе и при неудачной попытке ее удаления) должна быть однозначно снята, а не "Исполнена" с результатом "Отвергнута ТС".
Ушла ли заявка на биржу?, Заявка, выставляемая по стоп-заявке N [121500004], отвергнута торговой системой: Could not cancel order. [GW][14] "Не найдена заявка для удаления".
1. Раз присвоен номер, то не только уходила, но и была принята и выставлена. 2. Потому что стоп со связанной заявкой - это две заявки: стоп остается на сервере Квика до выполнения его условия, а связанный лимит сразу отправляется на биржу. Ваш номер 28763251083 - это как раз связанная лимит-заявка, висевшая на бирже. При срабатывании условия стопа Квик делает два действия - 1) снимает уже стоящую лимит заявку и 2) выставляет новую из стопа. Судя по вашей ситуации, у вас условие стопа выполнилось и последовали соответствующие телодвижения. Could not cancel order - это ответ шлюза (GW), то есть биржи о том, что не удалось выполнить первое действие - снять существующую связанную заявку 28763251083. По причине того, что она была, видимо, уже снята или исполнена. Или Квик передал неверный номер для снятия. Тысячи их, причин. 3. Это "шутки" Квика, так как биржа ни про какие стопы не ведает от слова совсем, и всей этой кухней управляет исключительно Квик. Биржа умеет лишь поставить/снять лимит.
Проблема, описанная в этой ветке, так за год и не решена.
Версия 7.0.4.10. В скрипте производится заказ всех сделок: CreateDataSource(..., ..., INTERVAL_TICK) SetUpdateCallback(...) Подписка выполняется только в скрипте, таблицы всех сделок в терминале не открываются.
Данные начинают поступать, callback-функция вызывается. При последующих перезапусках скрипта поведение также корректно.
Вывод: ошибка проявляется только при первом запуске скрипта и только при установленном до запуска соединении с сервером. Воспроизводится стабильно. Также установлено, что очистка данных при запуске (info.exe -clear) на описанное поведение не влияет.
Добрый день.
Ошибка будет исправлена в одной из очередных версий программы. Приносим извинения за причиненные неудобства.
Незаметно прошел еще год. Версия 7.4.0.79. Реально ли дождаться исправления ошибки?
Добрый день.
Да, конечно. Мы Вас незамедлительно известим.
Прошло три (!) года с момента обнаружения ошибки. Не лучше ли уже честно признаться, что для исправления требуется полная переделка системы и 100 человеко-лет ресурсов?
По приведенной выше методике биржи волатильность для каждого страйка оценивается с помощью параметрической кривой - "улыбки волатильности". Эта кривая - аналитическая модель с 5-ю параметрами (A, B, C, D, E). Про это и написано в методике непосредственно под приведенной выше таблицей:
"Параметры A, B, C, D, E, S устанавливаются таким образом, чтобы для каждого страйка опциона значение кривой волатильности для данного страйка было выше подразумеваемой волатильности лучшей заявки на покупку и одновременно ниже подразумеваемой волатильности лучшей заявки на продажу по опциону с данным страйком. Подбор указанных параметров кривой волатильности осуществляется один раз в одну минуту".
Таким образом, для решения задачи нужно брать лучшие биды и оффера в стаканах для каждого страйка и находить A, B, C, D, E так, чтобы кривая по этой формуле проходила указанным образом. Подбор этих параметров - класс математических задач, называемый "Curve fitting". Вот можно вкратце ознакомиться: https://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%B8%D0%B1%D0%BB%D0%B8%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D1... Там же есть список литературы.
Готовые алгоритмы и код дать не могу, так как это использовать не приходилось.
Николай Камынин написал: Но очень сомневаюсь, что Вы ее сможете запрограммировать.
Да ладно. Самое хитрое там - функция нормального распределения N(x). Но нам в помощь численные методы. Если интересна теория: 1. Hart, J.F. (1968). Computer Approximations. Наверно, наиболее цитируемая книга по численным методам. 2. Krishnamoorthy K. Handbook of Statistical Distributions with Applications (2006). Это, в частности, в области теории вероятностей. В ней надо смотреть раздел "10.10. Computing the Distribution Function".
Ну и код функции N(x) по этому методу, перенесенный на Луа. Точность 14 знаков этого приближения устроит?
Код
function NormCDF(x)
if type(x) ~= "number" then return end
local z = math.abs(x)
local p
if z < 7 then
p = math.exp(-z * z / 2) *
(((((((2.49338129315143e-02 * z + 0.604737992686704) * z + 6.81311678753268) * z +
46.0649519338751) * z + 202.102090717023) * z + 580.109897562909) * z +
1024.60809538334) * z + 913.167442114756) /
((((((((0.0625 * z + 1.51584331855598) * z + 17.1406995062578) * z +
116.979524577666) * z + 523.596091947383) * z + 1566.10462582845) * z +
3044.77121163622) * z + 3506.42059774909) * z + 1826.33488422951)
elseif z < 32 then
p = math.exp(-z * z / 2) / 2.506628274631 /
(z + 1 / (z + 2 / (z + 3 / (z + 4 / (z + 5 / (z + 6 / (z + 7)))))))
else
p = 0
end
return (x > 0) and (1 - p) or p
end
Не так страшно? С остальным в формулах Блэка-Шоулза наверно справитесь? Вот, например, расчет дельты колл опциона:
Код
function CallDelta(f, s, v, t)
return NormCDF((math.log(f / s) + v^2 * t / 2) / (v * t^0.5))
end