Mrak
Mrak личный блог
24 октября 2018, 17:35

Алготрейдинг в опционной торговле на Qlua. (МНОГО КОДА!)

Добрый день, уважаемые алготрейдеры!
Написал на днях некий алгоритм самостоятельного расчета греков опционов на 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
Алготрейдинг в опционной торговле на Qlua. (МНОГО КОДА!)



5 Комментариев
  • Vkt
    24 октября 2018, 18:05
    Как вариант:
    smart-lab.ru/blog/195508.php
    Только начиная с версии 7.6 Квика этот фреймворк не совсем корректно работает, надо hacktrade.lua допилить немного. Или старый Квик использовать.


  • Leo
    24 октября 2018, 21:19
    Остался Е. без новой рубашки
  • f0xtr0t
    25 октября 2018, 07:43
    «Подскажите, каким образом добавить в этот алгоритм выставление заявок после сравнения расчетных величин с теми, что транслирует биржа?» — про греки написал, а как заявки выставлять не разобрался?
  • Niktesla (бывш. Бабёр-Енот)
    25 октября 2018, 09:39
    греки, греки...
    греки — херня! 
    торговать то в профит как!?

Активные форумы
Что сейчас обсуждают

Старый дизайн
Старый
дизайн