Просто открыть сделку на инструменте проблема

Страницы: 1
RSS
Просто открыть сделку на инструменте проблема, Работает стабильно код на языке луа но дает ошибку
 
Код
local ver = '1.4'   --   06.03.2016
local lastPos = 0
local lastPrice = 0
local string_gmatch=string.gmatch
local string_find=string.find
local string_sub=string.sub
local string_len=string.len
local string_format=string.format
local math_modf=math.modf
local SeaGreen=12713921      --   RGB(193, 255, 193)
local RosyBrown=12698111   --   RGB(255, 193, 193)
local logFile
local trades = {} -- Таблица_01 - получили сделку
local _trades = {} -- временная таблица наших сделок для отлова дублей в QUIK ver. 7.1.0
local orders = {}   --   Таблица заявок
local scriptPath = getScriptPath()
local Terminal_Version=getInfoParam('VERSION')

local function versionLess(ver1,ver2)
   local begin,ver_1=0
   for ver_2 in string_gmatch(ver2,'%d+') do
      _,begin,ver_1=string_find(ver1,'(%d+)',begin+1)
      if ver_1~=ver_2 then return not ver_1 or ver_1+0<ver_2+0 end
   end
   return false
end
local  v = '6.17'
local table_insert
local table_remove
local table_concat
if versionLess(Terminal_Version,v ) then
   table_insert=table.ins ert
   table_remove=table.remove
   table_concat=table.concat
else   
   table_insert=table.sinsert
   table_remove=table.sremove
   table_concat=table.sconcat
end
-----

local dc = QTABLE_DEFAULT_COLOR

local testQuik = true -- подписка на OnTransReply, OnTrade, OnOrder
--local testQuik = false -- без подписки

function firm_id()
  for i = 0, getNumberOf("money_limits") - 1 do
    local row = getItem("money_limits", i)
    if row ~= nil and row.firmid ~= nil then
      local ss = tostring(string_sub(row.firmid, 2, 2))
      if ss == "C" or ss == "R" or ss == "B" then
        return tostring(row.firmid)
      end
    end
  end
  return nil
end

local is_forts = true
--настройки
function getInitParameter()
   if is_forts then
      account = ''
      classCode = ''
      secCode = 'RIM9'
      OpenSlippage = 50
      
      CLASS_CODE           = 'SPBFUT'        -- Код класса
      SEC_CODE             = 'RIM9'          -- Код инструмента
   else
      account="NL0011100043"
      ClientCode = "99914"
      classCode = 'QJSIM'
      secCode = 'SBER'
      OpenSlippage = 0.5
      firm_id = firm_id()
      message('firm_id = '..firm_id)
   end
   workSize = 4 -- рабочий размер
   logFileName1 = 'logFile1.txt'   -- файл для укороченного протоколирования коллбэков
   logFileName2 = 'logFile2.txt'   -- файл для печати всех полей коллбэков
end
---------------------------------------------------------
-- Округляет число до указанной точности
math_round = function(num, idp)
  local mult = 10^(idp or 0)
  return math.floor(num * mult + 0.5) / mult
end
-- Приводит переданную цену к требуемому для транзакции по инструменту виду
GetCorrectPrice = function(price) -- STRING
   -- Получает точность цены по инструменту
   local scale = getSecurityInfo(CLASS_CODE, SEC_CODE).scale
   -- Получает минимальный шаг цены инструмента
   local PriceStep = tonumber(getParamEx(CLASS_CODE, SEC_CODE, "SEC_PRICE_STEP").param_value)
   -- Если после запятой должны быть цифры
   if scale > 0 then
      price = tostring(price)
      -- Ищет в числе позицию запятой, или точки
      local dot_pos = price:find('.')
      local comma_pos = price:find(',')
      -- Если передано целое число
      if dot_pos == nil and comma_pos == nil then
         -- Добавляет к числу ',' и необходимое количество нулей и возвращает результат
         price = price..','
         for i=1,scale do price = price..'0' end
         return price
      else -- передано вещественное число         
         -- Если нужно, заменяет запятую на точку 
         if comma_pos ~= nil then price:gsub(',', '.') end
         -- Округляет число до необходимого количества знаков после запятой
         price = math_round(tonumber(price), scale)
         -- Корректирует на соответствие шагу цены
         price = math_round(price/PriceStep)*PriceStep
         price = string.gsub(tostring(price),'[\.]+', ',')
         return price
      end
   else -- После запятой не должно быть цифр
      -- Корректирует на соответствие шагу цены
      price = math_round(price/PriceStep)*PriceStep
      return tostring(math.floor(price))
   end
end

-- Возвращает корректную цену для рыночной заявки по текущему инструменту (принимает 'S',или 'B')
GetPriceForMarketOrder = function(operation) -- STRING
   -- Получает минимальный шаг цены инструмента
   local PriceStep = tonumber(getParamEx(CLASS_CODE, SEC_CODE, "SEC_PRICE_STEP").param_value)
   -- В зависимости от направления
   if operation == 'B' then -- BUY
      -- Пытается получить максимально возможную цену для инструмента
      local PriceMax = tonumber(getParamEx(CLASS_CODE,  SEC_CODE, 'OFFER').param_value)
      -- Если максимально возможная цена получена
      if PriceMax ~= nil and PriceMax ~= 0 then
         -- Возвращает ее в нужном для транзакции формате
         return GetCorrectPrice(PriceMax)
      -- Иначе, максимально возможная цена не получена
      else
         -- Получает цену последней сделки
         local Last = tonumber(getParamEx(CLASS_CODE,  SEC_CODE, 'LAST').param_value)
         -- Возвращает ее в нужном для транзакции формате, увеличив перед этим на 50 шагов цены
         return GetCorrectPrice(Last + 50*PriceStep)
      end
   else                     -- SELL
      -- Пытается получить минимально возможную цену для инструмента
      local PriceMin = tonumber(getParamEx(CLASS_CODE,  SEC_CODE, 'BID').param_value)
      -- Если минимально возможная цена получена
      if PriceMin ~= nil and PriceMin ~= 0 then
         -- Возвращает ее в нужном для транзакции формате
         return GetCorrectPrice(PriceMin)
      -- Иначе, минимально возможная цена не получена
      else
         -- Получает цену последней сделки
         local Last = tonumber(getParamEx(CLASS_CODE,  SEC_CODE, 'LAST').param_value)
         -- Возвращает ее в нужном для транзакции формате, уменьшив перед этим на 50 шагов цены
         return GetCorrectPrice(Last - 50*PriceStep)
      end
   end 
end

function isModule(modname)
   if not package.loaded[modname] then   -- Если модуль modname не загружен ранее
      for i, v in ipairs(package.loaders) do
         local loader = v(modname)
         if type(loader) == 'function' then
            package.preload[modname] = loader
            return true
         end
      end
   end
end
--
local modname = "socket.socket"
local isSocket
local _mes
if isModule(modname) then
   isSocket = require(modname)
else   
   _mes = modname..' No exist!'; message(_mes,3)
end


function getHRTime()
   -- возвращает время с милисекундами или без них, в зависимости от наличия socket.socket
   if isSocket then 
      local now = socket.gettime() 
      return string_format("%s,%03d",os.date("%X",now),select(2,math_modf(now))*1000)
   else 
      return os.date("%X", os.time()) 
   end
end
--

function event_callback_tblH(t_id, msg, par1, par2)
   if msg == QTABLE_LBUTTONDOWN then   -- нажата левая кнопка мыши
      local mes = ''
      lastPos = futures_position()
      local status = tonumber(getParamEx(classCode, secCode,"status").param_value)
      if status ~= 1 or par1 == 1 then -- если бумага не торгуется, заявку не подаем
         Highlight(t_id, par1, par2, RosyBrown, dc, 500)      -- подсветка, RosyBrown
         if status ~= 1 then
            mes = 'error cliring'
            
            message(mes); io_log(mes);
         end
         return
      end
      Highlight(t_id, par1, par2, SeaGreen, dc, 500)      -- подсветка SeaGreen
      if par1 == 2 and par2 == 1 then
         if lastPos < 0 then
            mes = secCode..'; Pressed: Buy, '..-lastPos
            Buy(classCode, secCode, -lastPos, 'CloseShort')
         elseif    lastPos == 0 then
            mes = secCode..'; Pressed: Buy, '..workSize
            Buy(classCode, secCode, workSize, 'OpenLong')
         else
            mes = secCode..'; Pressed: Buy. My v longah ne pokupaem!'
         end
      elseif par1 == 2 and par2 == 2 then   -- продать, левая кнопка
         if lastPos > 0 then
            mes = secCode..'; Pressed: Sell, '..lastPos
            Sell(classCode, secCode, lastPos, 'CloseLong')
         elseif    lastPos == 0 then
            mes = secCode..'; Pressed: Sell, '..workSize
            Sell(classCode, secCode, workSize, 'OpenShort')
         else
            mes = secCode..'; Pressed: Sell. my v shortah ne prodaem!'
         end
      elseif par1 == 2 and par2 == 3 then   -- закрыть позиции
         if lastPos > 0 then
            mes = secCode..'; Pressed: закрыть лонги, '..lastPos
            Sell(classCode, secCode, lastPos, 'CloseAll')
         elseif    lastPos < 0 then
            mes = secCode..'; Pressed: закрыть шорты, '..-lastPos
            Buy(classCode, secCode, -lastPos, 'CloseAll')
         else
            mes = secCode..'; Pressed: закрыть. No position for close!'
         end
      elseif par1 == 3 and par2 == 1 then
         if lastPos < 0 then
            mes = secCode..'; Pressed: Buy-, '..-lastPos
            BuyBid(classCode, secCode, -lastPos, 'CloseShort')
         elseif    lastPos == 0 then
            BuyBid(classCode, secCode, workSize, 'OpenLong')
            mes = secCode..'; Pressed: Buy-, '..workSize
         else
            mes = secCode..'; Pressed: Buy-. My v longah ne pokupaem!'
         end
      elseif par1 == 3 and par2 == 2 then
         if lastPos > 0 then
            SellOffer(classCode, secCode, lastPos, 'CloseLong')
            mes = secCode..'; Pressed: Sell+, '..lastPos
         elseif    lastPos == 0 then
            SellOffer(classCode, secCode, workSize, 'OpenShort')
            mes = secCode..'; Pressed: Sell+, '..workSize
         else
            mes = secCode..'; Pressed: Sell+. Мmy v shortah ne prodaem!'
         end
      elseif par1 == 3 and par2 == 3 then
         mes = secCode..'; Pressed: Remove all orders!'
         KillOrders()
      end
      message(mes); io_log(mes);
   elseif msg == QTABLE_CLOSE then
      OnStop()
   end   
end
--

QTable ={}
QTable.__index = QTable
-- Создать и инициализировать экземпляр таблицы QTable
function QTable.new()
   local t_id = AllocTable()
   if t_id ~= nil then
      q_table = {}
      setmetatable(q_table, QTable)
      q_table.t_id=t_id
      q_table.caption = ""
      q_table.created = false
      q_table.curr_col=0
      -- таблица с описанием параметров столбцов
      q_table.columns={}
      return q_table
   else
      return nil
   end
end
tblH = QTable:new() -- для ручной торговли
--

function get_trans_id()
   local s = tostring(os.clock())
   local x, g = string_find(s, "(%d+)")
   s = string_sub(s, g + 2)
   for i = 1, 3 - string_len(s) do
      s = "0" .. s
   end
   return os.date("%H%M%S") .. s
end
--
--- Функция отправки ордера
function send_order(client, class, seccode, account, operation, quantity, price)
   
   local gcp=GetPriceForMarketOrder(operation) 
   local trans_id = get_trans_id()
   local trans_params = {
      CLASSCODE = class,
      CLIENT_CODE = client,
      SECCODE = seccode,
      ACCOUNT = account,
      TYPE = new_type,
      TRANS_ID = trans_id,
      OPERATION = operation,
      QUANTITY = tostring(quantity),
      PRICE = tostring(gcp),
      ACTION = "NEW_ORDER"
      }
   return sendTransaction(trans_params)
end
--

function Buy(classCode, secCode, size, action)
   local best_offer = getParamEx(classCode, secCode, "offer").param_value
   local buyPrice = best_offer + (OpenSlippage or 0)
   local res = send_order(action, classCode, secCode, account, "B", size, buyPrice)
   if string_len(res) ~= 0 then
      local mes = 'Error: '..res..', '.. action..', '..secCode..', '.."B"..', '..size..', price='..buyPrice
      message(mes,3); io_log(mes);
   end
end
--

function Sell(classCode, secCode, size, action)
   local best_bid = getParamEx(classCode, secCode, "bid").param_value
   local sellPrice = best_bid - (OpenSlippage or 0)
   local res = send_order(action, classCode, secCode, account, "S", size, sellPrice)
   if string_len(res) ~= 0 then
      local mes = 'Error: '..res..', '.. action..', '..secCode..', '.."S"..', '..size..', price='..sellPrice
      message(mes,3); io_log(mes);
   end
end
--

function BuyBid(classCode, secCode, size, action)
   local best_bid = getParamEx(classCode, secCode, "bid").param_value
   local buyPrice = best_bid - (OpenSlippage or 0)
   local res = send_order(action, classCode, secCode, account, "B", size, buyPrice)
   if string_len(res) ~= 0 then
      local mes = 'Error: '..res..', '.. action..', '..secCode..', '.."B"..', '..size..', price='..buyPrice
      message(mes,3); io_log(mes);
   end
end
--

function SellOffer(classCode, secCode, size, action)
   local best_offer = getParamEx(classCode, secCode, "offer").param_value
   local sellPrice = best_offer + (OpenSlippage or 0)
   local res = send_order(action, classCode, secCode, account, "S", size, sellPrice)
   if string_len(res) ~= 0 then
      local mes = 'Error: '..res..', '.. action..', '..secCode..', '.."S"..', '..size..', price='..sellPrice
      message(mes,3); io_log(mes);
   end
end
--

function KillOrders()
   local NumberOf = getNumberOf("orders")
   for i = 0, NumberOf - 1 do
      local ord = getItem("orders", i)
      if ord.sec_code == secCode and ord.account == account  then
         local order_flag = get_order_status(ord.flags)
         if order_flag.status == "active" then
            trans_id = get_trans_id()
            local trans_params = {
                  ["CLASSCODE"] = classCode,
                  ["TRANS_ID"] = trans_id,
                  ["ACTION"] = "KILL_ORDER",
                  ["ORDER_KEY"] = tostring(ord.order_num)
                  }
            local res =  sendTransaction(trans_params)
            if 0 < string_len(res) then
               local mes = 'Error: '..res
               message(mes,3); io_log(mes);
            end
         end
      end
   end
end
--

function HandleBS()
   local t = tblH.t_id
   AddColumn(t, 1, 'Bumaga', true,QTABLE_CACHED_STRING_TYPE,12)
   AddColumn(t, 2, 'Tcp', true,QTABLE_STRING_TYPE,12)
   AddColumn(t, 3, 'Last price.', true,QTABLE_STRING_TYPE,17)
   CreateWindow(t)
   SetWindowCaption(t, "SuperScalp "..ver)   --SetWindowCaption(t, "Scalper:"..account)
   SetWindowPos(t, 0, 100, 250, 120)
   local li=InsertRow(t, -1)
   SetCell(t, li, 1, secCode)
   SetCell(t, li, 2, lastPos)
   SetCell(t, li, 3, '7503')   --Ожидание
   local li=InsertRow(t, -1)
   SetCell(t, li, 1, 'Buy')
   SetCell(t, li, 2, 'Sell')
   SetCell(t, li, 3, 'Close')
   local li=InsertRow(t, -1)
   SetCell(t, li, 1, 'Buy —')
   SetCell(t, li, 2, 'Sell +')
   SetCell(t, li, 3, 'Close All')
   SetTableNotificationCallback(t,event_callback_tblH)
end
--

--прочитать ТТП и вытащить ТЧП.
function futures_position()
   if is_forts then
      local count=getNumberOf("futures_client_holding") --Позиции по клиентским счетам (фьючерсы)
      for i=0,count-1, 1 do
         local row=getItem("futures_client_holding",i)
         if row.trdaccid~=nil then
            local seccode=row.sec_code      --Код фьючерсного контракта, "Инструмент"
            local totn=row.totalnet         --Текущие чистые позиции   "ТЧП"
            if seccode == secCode then
               return totn
            end
         end
      end
   else
      local t = getDepoEx(firm_id, ClientCode, secCode, account, 0)
      if t then
         local T = t.currentbal
         SetCell(tblH.t_id, 1, 2, tostring(T))
         positionColor(T)
         return T
      end
   end
   return 0
end
--

function positionColor(tot)
   if tot>0 then
      SetColor(tblH.t_id,1,2, SeaGreen, dc, dc, dc)   -- подсветка SeaGreen
   elseif tot<0 then
      SetColor(tblH.t_id,1,2, RosyBrown, dc, dc, dc)   -- подсветка, RosyBrown
   else   
      SetColor(tblH.t_id,1,2,dc, dc, dc, dc)
   end 
end
--

function get_order_status(flags)
  local rt = {}
  local band = bit.band
  local tobit = bit.tobit
  if band(tobit(flags), 1) ~= 0 and band(tobit(flags), 2) == 0 then
    rt.status = "active"
  elseif band(tobit(flags), 1) == 0 and band(tobit(flags), 2) ~= 0 then
    rt.status = "cancelled"
  elseif band(tobit(flags), 1) == 0 and band(tobit(flags), 2) == 0 then
    rt.status = "filled"
  else
    rt.status = "unknown"
  end
  if band(tobit(flags), 4) ~= 0 then
    rt.operation = "S"
  else
    rt.operation = "B"
  end
  return rt
end
--

--запись лога с текущим простым временем
function io_log(str)
   local file, err = io.open(logFile, "a")
   assert(file, "Error write "..logFile..", \n"..str)
   local str0 = getHRTime()   -- время с миллисекундами
   str0 = str0..'; '.. str
   file:write(str0 .. "\n")
   file:flush()
   file:close()
   return true
end
--

if testQuik then
   -- 2.2.17 - Функция вызывается терминалом QUIK при получении ответа на транзакцию пользователя.
   function OnTransReply(reply)
      if reply.account == account then
         if running then
            local mes =  reply.sec_code..'; OnTrans, o_n '..reply.order_num..', '..tostring(reply.price)..' x '..
            tostring(reply.quantity)..', t_id = '..reply.trans_id
            message(mes); io_log(mes);
         end
         toLog(scriptPath..'\\'..logFileName2,reply, 'reply')
      end
   end
   -- 2.2.3 Функция вызывается терминалом QUIK при получении сделки.
   function OnTrade(trade)
      if trade.account == account then   -- только если заявка из нашего счета - 01.11.2014
         if running then
            if not _trades[trade.trade_num] then
               local mes = trade.sec_code..'; OnTrade, 1, o_n = '..trade.order_num..', t_n = '..trade.trade_num..' ('..trade.price..'x'..trade.qty..')'
               message(mes); io_log(mes);
               _trades[trade.trade_num] = true  -- Добавим в очередь
               _trades[trade.tradenum] = 1
               table_insert(trades,trade)
            else   
               _trades[trade.tradenum] = _trades[trade.tradenum] + 1
               local mes = trade.sec_code..'; OnTrade, '.._trades[trade.tradenum]..', o_n = '..trade.order_num..', t_n = '..trade.trade_num..' ('..trade.price..'x'..trade.qty..')'
               message(mes); io_log(mes);
            end
            toLog(scriptPath..'\\'..logFileName2,trade, 'trade')
         end
      end
   end
   --2.2.4   OnOrder   Функция вызывается терминалом QUIK при получении новой заявки или при изменении параметров существующей заявки.
   function OnOrder(order)
      if order.account == account then
         local order_flag = get_order_status(order.flags)
         local op = order_flag.operation
         local mes = order.sec_code..'; OnOrder, '..op.. ', o_n = '..order.order_num..' ('..order.price..'x'..order.qty.."), t_id = "..order.trans_id..', flag = '..order.flags..", "..order.brokerref..", balance = "..order.balance..', '..order_flag.status
         io_log(mes)
         toLog(scriptPath..'\\'..logFileName2,order, 'order')
      end   
   end
end
--

function toLog(file_path,value,txt)
   -- запись в файл параметра value
   -- value может быть числом, строкой или таблицей
   -- file_path  -  путь к файлу
   -- файл открывается на дозапись и закрывается после записи строки
   local now = getHRTime()   -- c мс
   if file_path~=nil and value~=nil then
      local lf, err = io.open(file_path, "a")
      assert(lf, "Ошибка записи "..file_path..", \n")
      if lf~=nil then
         lf:write(txt.."\n")
         if type(value)=="string" or type(value)=="number" then
            lf:write(now.." "..value.."\n")
         elseif type(value)=='boolean' then
            lf:write(now.." "..tostring(value).."\n")
         elseif type(value)=="table" then
            lf:write(now.."\n"..table2string(val ue).."\n")
         end
         lf:flush()
         if io.type(lf)=="file" then   lf:close() end
      end
   end
end
--

function table2string(table)
   local k,v,str=0,0,""
   for k,v in pairs(table) do
      if type(v)=="string" or type(v)=="number" then
         str=str..k.."="..v..';\n'   --  в 1
         --str=str..k.."="..v..'; '   --  в 2
      elseif type(v)=="table"then
         str=str..k.."={\n"..table2string(v).."};\n"
      elseif type(v)=="function" or type(v)=='boolean' then
         str=str..k..'='..tostring(v)..';\n'
      end
   end
   return str
end
--

-- 2.2.8   OnFuturesClientHolding
-- Функция вызывается терминалом QUIK при изменении позиции по срочному рынку.
function OnFuturesClientHolding(tab)
   local sec_code = tab.sec_code
   local totalnet = tab.totalnet
   if running and sec_code == secCode then -- выбираем нужную нам бумагу
      local t= tonumber(totalnet)
      if t ~= nil then
         SetCell(tblH.t_id, 1, 2, tostring(totalnet), totalnet)
         positionColor(t)
      end
   end
end
--
-- 2.2.5  Функция вызывается терминалом QUIK при получении изменений текущей позиции по счету.
-- (ТОЛЬКО ДЛЯ БРОКЕРА).
function OnAccountBalance(acc_bal)
   if acc_bal.sec_code==secCode then
      local t= acc_bal.currentpos
      if t ~= nil then
         SetCell(tblH.t_id, 1, 2, tostring(t))
         positionColor(t)
      end
   end
end

--   2.2.18   OnParam
--   Функция вызывается терминалом QUIK при изменении текущих параметров.
function OnParam(class, seccode)
   if seccode == secCode then -- выбираем нужную нам бумагу
      local lp = tonumber(getParamEx(class, seccode, "last").param_value)
      if lp > lastPrice then
         Highlight(tblH.t_id, 1, 3, SeaGreen, dc, 1000)      -- подсветка мягкий, зеленый
         lastPrice = lp   -- цена последней сделки
         SetCell(tblH.t_id, 1, 3, tostring(lastPrice))
      elseif lp < lastPrice then
         Highlight(tblH.t_id, 1, 3, RosyBrown, dc, 1000)      -- подсветка
         lastPrice = lp
         SetCell(tblH.t_id, 1, 3, tostring(lastPrice))
      end
   end   
end
--

-- 2.2.24 OnStop
-- Функция вызывается терминалом QUIK при остановке скрипта из диалога управления и при
-- закрытии терминала QUIK.
function OnStop()
   local mes = 'Stop SuperScalp.'
   message(mes); io_log(mes);
   running = false
   DestroyTable(tblH.t_id)
end
--

-- 2.2.25 OnInit
-- Функция вызывается терминалом QUIK перед вызовом функции main().
function OnInit()
   getInitParameter()
   logFile = scriptPath..'\\'..logFileName1
   local mes = 'Start SuperScalp '..ver..', QUIK '..Terminal_Version
   message(mes); io_log(mes);
   running = true
   HandleBS()
   lastPos = futures_position()
   SetCell(tblH.t_id, 1, 2, tostring(lastPos))
   positionColor(lastPos)
end
--

-- 2.2.26 main
-- Функция, реализующая основной поток выполнения в скрипте.
function main()
   while running do
      sleep(1000)
      if not is_forts then
         local t = getDepoEx(firm_id, ClientCode, secCode, account, 0)
         local T = t.currentbal
         SetCell(tblH.t_id, 1, 2, tostring(T))
         positionColor(T)
      end
      
   end
end
 
Нормально работает но каждый раз после рестарта терминала выдает ошибку error cliring  один раз на старте. Это довольно напрягает и можно не заметить что сделка не состоялась.
Страницы: 1
Читают тему
Наверх