Добрый день, уважаемые алготрейдеры!
Написал на днях некий алгоритм самостоятельного расчета греков опционов на Qlua срочном рынке ММВБ-РТС, которые
показываются в виде таблицы значений в Quik.
Подскажите, каким образом добавить в этот алгоритм выставление заявок после сравнения расчетных величин с теми, что транслирует биржа?
RiskFree=5.6/100
BaseClassCode = "SPBFUT"
ClassCode = "SPBOPT"
BaseSecList = "SiZ8"
SecList = getClassSecurities(ClassCode)
INTERVAL = 1000
doLogging=true log_file=getScriptPath() .. "\\last.csv"
tbl = {
["caption"]="Greek",
[1]="Название",
[2]="Код опциона",
[3]="Тип опциона",
[4]="Баз. актив",
[5]="Расчетная цена",
[6]="Страйк",
[7]="Волатильность",
[8]="До исполнения",
[9]="Дельта",
[10]="Гамма(%)",
[11]="Тэта",
[12]="Вега",
[13]="Ро",
[14]="Цена",
[15]="last",
[16]="quik",
["t_id"]=0
}
abTable = {}
BaseCol = {}
Sec2row = {}
file = nil
Sep = ";"
YearLen=365.0
WORK = true
CALC = false
G_ROW = -1
if (BaseSecList == "") or (BaseSecList == nil) then
BaseSecList = getClassSecurities(BaseClassCode)
end
if (SecList == "") or (SecList == nil) then
SecList = getClassSecurities(ClassCode)
end
function Logging(str)
if file~=nil and doLogging then
file:write(str .. "\n")
file:flush()
end
end
function N(x)
if (x > 10) then
return 1
elseif (x < -10) then
return 0
else
local t = 1 / (1 + 0.2316419 * math.abs(x))
local p = 0.3989423 * math.exp(-0.5 * x * x) * t * ((((1.330274 * t - 1.821256) * t + 1.781478) * t - 0.3565638) * t + 0.3193815)
if x > 0 then
p=1-p
end
return p
end
end
function pN(x)
return math.exp(-0.5 * x * x) / math.sqrt(2 * math.pi)
end
function PriceOpt(tmpGreek,tmpParam)
local b = tmpParam.volatility / 100
local S = tmpParam.settleprice
local Tt = tmpParam.DAYS_TO_MAT_DATE / YearLen
local K = tmpParam.strike
local r = RiskFree
local delta = tmpGreek.Delta
local rho = tmpGreek.Rho
local d1 = (math.log(S / K) + (r + b * b * 0.5) * Tt) / (b * math.sqrt(Tt))
local d2 = d1-(b * math.sqrt(Tt))
local e = math.exp(-1 * r * Tt)
local Price = 0
if tmpParam.Optiontype == "Call" then
Price = S*e * N(d1) - K * e * N(d2)
else
Price = K * e * N(-1 * d2)-S*e * N(-1*d1)
end
if Price<1 then
Price = 1
end
return {["Price"] = Price}
end
function Greek(tmpParam)
local b = tmpParam.volatility / 100
local S = tmpParam.settleprice
local Tt = tmpParam.DAYS_TO_MAT_DATE / YearLen
local K = tmpParam.strike
local r = RiskFree
local d1 = (math.log(S / K) + (r + b * b * 0.5) * Tt) / (b * math.sqrt(Tt))
local d2 = d1-(b * math.sqrt(Tt))
local Delta = 0
local Gamma = 0
local Theta = 0
local Vega = 0
local Rho = 0
local e = math.exp(-1 * r * Tt)
Gamma = pN(d1) / (S * b * math.sqrt(Tt))
Vega = S * e * pN(d1) * math.sqrt(Tt)
Theta = (-1 * S * b * e * pN(d1)) / (2 * math.sqrt(Tt))
if tmpParam.Optiontype == "Call" then
Delta = e * N(d1)
Theta = Theta - (r * K * e * N(d2)) + r * S * e * N(d1)
Rho = K * Tt * e * N(d2)
else
Delta = -1 * e * N(-1*d1)
Theta = Theta + (r * K * e * N(-1 * d2)) - r * S * e * N(-1 * d1)
Rho = -1 * K * Tt * e * N(-1 * d2)
end
return {
["Delta"] = Delta,
["Gamma"] = 100 * Gamma,
["Theta"] = Theta / YearLen,
["Vega"] = Vega / 100,
["Rho"] = Rho / 100 }
end
function GetRow(ID,row)
local rows, col = GetTableSize(ID)
local result = ""
if rows~=nil and row<=rows then
for i=1,col do
result=result..GetCell(ID,row,i).image .. Sep
end
end
return result
end
function CSV(T)
function FTEXT(V)
V=tostring(V)
if (string.len(V)==1) or (string.len(V)==5) then
V="0".. V
end
return V
end
local temp = os.date("*t")
local Fname =getScriptPath() .. "\\" .. FTEXT(temp.year) .. FTEXT(temp.month)
.. FTEXT(temp.day) .. ".csv"
CSVFile = io.open(Fname, "w+")
if CSVFile~=nil then
local rows, col = GetTableSize(T.t_id)
for i=1,col do
CSVFile:write(T[i] .. Sep)
end
CSVFile:write("\n")
for i=1,rows do
CSVFile:write(GetRow(T.t_id,i).."\n")
end
CSVFile:flush()
CSVFile:close()
message("Файл успешно сохранен:\n"..Fname, 1)
else
message("Ошибка при сохранении файла:\n"..Fname, 3)
end
end
function round(num, idp)
local mult = 10^(idp or 0)
return math.floor(num * mult + 0.5) / mult
end
function comma_value(n)
local left,num,right = string.match(n,'^([^%d]*%d)(%d*)(.-)$')
return left..(num:reverse():gsub('(%d%d%d)','%1 '):reverse())..right
end
function CreateDataSourceEX(Class,Sec,Par)
local ds,err = CreateDataSource(Class, Sec, INTERVAL_TICK, Par)
if ds==nil then
message("Ошибка при получении параметра "..Par..":\n"..err, 3)
return false
else
ds:SetEmptyCallback()
while ds:Size()==nil do
sleep(100)
end
return true
end
end
function Stop()
if doLogging then
file:close()
end
WORK = false
end
function Calculate(row,do_calc)
if (row~=nil) and (row>=0) and (do_calc) then
local T=BaseCol[row]
local tmpParam ={
["Optiontype"] = T.Optiontype,
["settleprice"] = getParamEx(BaseClassCode,T.Optionbase,"settleprice").param_value+0,
["strike"] = getParamEx(ClassCode,T.SecCode,"strike").param_value+0,
["volatility"] = getParamEx(ClassCode,T.SecCode,"volatility").param_value+0,
["DAYS_TO_MAT_DATE"] = T.DAYS_TO_MAT_DATE,
["last"] = getParamEx(ClassCode,T.SecCode,"last").param_value+0,
["THEORPRICE"] = getParamEx(ClassCode,T.SecCode,"THEORPRICE").param_value+0
}
local tmpGreek = Greek(tmpParam)
local tmpPrice = PriceOpt(tmpGreek,tmpParam)
SetCell(tbl.t_id, row, 5, comma_value(tmpParam.settleprice), tmpParam.settleprice) -- "Расчетная цена",
SetCell(tbl.t_id, row, 6, comma_value(tmpParam.strike), tmpParam.strike) --"Страйк",
SetCell(tbl.t_id, row, 7, tostring(tmpParam.volatility), tmpParam.volatility) -- "Волатильность",
SetCell(tbl.t_id, row, 8, tostring(tmpParam.DAYS_TO_MAT_DATE), tmpParam.DAYS_TO_MAT_DATE) --"До исполнения",
SetCell(tbl.t_id, row, 9, tostring(round(tmpGreek.Delta,2)), tmpGreek.Delta) --"Дельта",
SetCell(tbl.t_id, row, 10, tostring(round(tmpGreek.Gamma,4)), tmpGreek.Gamma) -- "Гамма(%)",
SetCell(tbl.t_id, row, 11, tostring(round(tmpGreek.Theta,2)), tmpGreek.Theta) -- "Тэта",
SetCell(tbl.t_id, row, 12, tostring(round(tmpGreek.Vega,2)), tmpGreek.Vega) -- "Вега",
SetCell(tbl.t_id, row, 13, tostring(round(tmpGreek.Rho,2)), tmpGreek.Rho) -- "Ро",
SetCell(tbl.t_id, row, 14, comma_value(round(tmpPrice.Price,2)), tmpPrice.Price)
SetCell(tbl.t_id, row, 15, tostring(tmpParam.last), tmpParam.last)
SetCell(tbl.t_id, row, 16, tostring(tmpParam.THEORPRICE), tmpParam.THEORPRICE)
Logging(os.date().. Sep .. GetRow(tbl.t_id,row))
end
return false
end
function f_cb(t_id,msg,par1,par2)
if (msg==QTABLE_CHAR) and (par2==19) then
CSV(tbl)
end
if (msg==QTABLE_CLOSE) then
Stop()
end
end
function OnStop()
Stop()
DestroyTable(tbl.t_id)
end
function OnInit()
local STR = ""
if doLogging then
file = io.open(log_file, "w+")
end
tbl.t_id = AllocTable()
for i=1,table.maxn(tbl) do
if i<=4 then
AddColumn(tbl.t_id, i, tbl[i], true, QTABLE_CACHED_STRING_TYPE, string.len(tbl[i])*2)
else
AddColumn(tbl.t_id, i, tbl[i], true, QTABLE_DOUBLE_TYPE, 10)
end
if doLogging then
STR=STR..tbl[i]..Sep
end
end
Logging("Дата Время".. Sep .. STR)
CreateWindow(tbl.t_id)
SetWindowCaption(tbl.t_id,tbl.caption) SetTableNotificationCallback(tbl.t_id, f_cb)
end
function OnParam(class, sec)
if (class==ClassCode) and (WORK) and (string.find(SecList,sec)~=nil) then
G_ROW = Sec2row[sec]
if (G_ROW~=nil) and (G_ROW>=0) then
Highlight(tbl.t_id, G_ROW, QTABLE_NO_INDEX, RGB(255,0,0), QTABLE_DEFAULT_COLOR, 1000)
CALC=true
CALC=Calculate(G_ROW,CALC)
end
end
end
function main()
WORK = false
CALC=true
for SecCode in string.gmatch(SecList, "([^,]+)") do --перебираем опционы по очереди.
local Optionbase=getParamEx(ClassCode,SecCode,"optionbase").param_image
local Optiontype=getParamEx(ClassCode,SecCode,"optiontype").param_image
if (string.find(BaseSecList,Optionbase)~=nil) and (Optiontype=="Call") then
local row = InsertRow(tbl.t_id,-1)
local T={
["Name"] = getSecurityInfo(ClassCode,SecCode).name,
["SecCode"] = SecCode,
["Optiontype"] = Optiontype,
["Optionbase"] = Optionbase,
["DAYS_TO_MAT_DATE"] = getParamEx(ClassCode,SecCode,"DAYS_TO_MAT_DATE").param_value+0
}
BaseCol[row]=T
Sec2row[SecCode]=row
SetCell(tbl.t_id, row, 1, BaseCol[row].Name) -- "Название опциона",
SetCell(tbl.t_id, row, 2, BaseCol[row].SecCode) --"Код опциона",
SetCell(tbl.t_id, row, 3, BaseCol[row].Optiontype) -- "Тип опциона",
SetCell(tbl.t_id, row, 4, BaseCol[row].Optionbase) --"Баз. актив",
CreateDataSourceEX(BaseClassCode,T.Optionbase,"settleprice")
CreateDataSourceEX(ClassCode,T.SecCode,"strike")
CreateDataSourceEX(ClassCode,T.SecCode,"volatility")
CreateDataSourceEX(ClassCode,T.SecCode,"THEORPRICE")
CALC=Calculate(row,true)
end
end
for SecCode in string.gmatch(SecList, "([^,]+)") do
local Optionbase=getParamEx(ClassCode,SecCode,"optionbase").param_image
local Optiontype=getParamEx(ClassCode,SecCode,"optiontype").param_image
if (string.find(BaseSecList,Optionbase)~=nil) and (Optiontype=="Put") then
local row = InsertRow(tbl.t_id,-1)
local T={
["Name"] = getSecurityInfo(ClassCode,SecCode).name,
["SecCode"] = SecCode,
["Optiontype"] = Optiontype,
["Optionbase"] = Optionbase,
["DAYS_TO_MAT_DATE"] = getParamEx(ClassCode,SecCode,"DAYS_TO_MAT_DATE").param_value+0
}
BaseCol[row]=T
Sec2row[SecCode]=row
SetCell(tbl.t_id, row, 1, BaseCol[row].Name) -- "Название опциона",
SetCell(tbl.t_id, row, 2, BaseCol[row].SecCode) --"Код опциона",
SetCell(tbl.t_id, row, 3, BaseCol[row].Optiontype) -- "Тип опциона",
SetCell(tbl.t_id, row, 4, BaseCol[row].Optionbase) --"Баз. актив",
CreateDataSourceEX(BaseClassCode,T.Optionbase,"settleprice")
CreateDataSourceEX(ClassCode,T.SecCode,"strike")
CreateDataSourceEX(ClassCode,T.SecCode,"volatility")
CreateDataSourceEX(ClassCode,T.SecCode,"last")
CreateDataSourceEX(ClassCode,T.SecCode,"THEORPRICE")
CALC=Calculate(row,true)
end
end
WORK = true
while WORK do
sleep(INTERVAL)
end
end
smart-lab.ru/blog/195508.php
Только начиная с версии 7.6 Квика этот фреймворк не совсем корректно работает, надо hacktrade.lua допилить немного. Или старый Квик использовать.
А автору сего поста я бы посоветовал глянуть в сторону QL — она дубовая, здоровая, но зато надежная как железный лом.
но если по правде, то ан самом деле все эти расчеты херня представляют собой сугубо теоретическую ценность до тех пор пока вы не научитесь влёт считать цену закрытия в 18.38.
греки — херня!
торговать то в профит как!?