Код |
---|
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 |
Yerlan (Автор тем)
Просто открыть сделку на инструменте проблема, Работает стабильно код на языке луа но дает ошибку
C++ + Луа, Стандартные библиотеки
C++ или луа, На каком выборе остановится на чистом с++ или луа?
Фьючесный контракт некорректные цены, EDH9 цена в стакане на данный момент 1.1306
|