Здравствуйте. Помогите поправить код так, чтобы можно было добавлять не одну акцию, а не сколько. Очень буду благодарен. Вроде просто. А мне не по силам.
Код |
---|
local ver = '1.4' 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="XXX" ClientCode = "XXX" classCode = 'SPBXM' secCode = 'A' OpenSlippage = 0.5 firm_id = firm_id() message('firm_id = '..firm_id) --else --account = 'XXX' --classCode = 'SPBFUT' --secCode = 'SRH6' --OpenSlippage = 50 end workSize = 1 -- Размер Лота logFileName1 = 'logFile1.txt' -- Файл для укороченного протоколирования коллбэков logFileName2 = 'logFile2.txt' -- Файл для печати всех полей коллбэков 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..' Отсутствует!'; 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 = 'Ошибка: клиринг!' 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..'; Нажато: Купить, '..-lastPos Buy(classCode, secCode, -lastPos, 'CloseShort') elseif lastPos == 0 then mes = secCode..'; Нажато: Купить, '..workSize Buy(classCode, secCode, workSize, 'OpenLong') else mes = secCode..'; Нажато: Купить. Мы в лонгах, не покупаем!' end elseif par1 == 2 and par2 == 2 then -- продать, левая кнопка if lastPos > 0 then mes = secCode..'; Нажато: Продать, '..lastPos Sell(classCode, secCode, lastPos, 'CloseLong') elseif lastPos == 0 then mes = secCode..'; Нажато: Продать, '..workSize Sell(classCode, secCode, workSize, 'OpenShort') else mes = secCode..'; Нажато: Продать. Мы в шортах, не продаем!' end elseif par1 == 2 and par2 == 3 then -- закрыть позиции if lastPos > 0 then mes = secCode..'; Нажато: Закрыть лонги, '..lastPos Sell(classCode, secCode, lastPos, 'CloseAll') elseif lastPos < 0 then mes = secCode..'; Нажато: Закрыть шорты, '..-lastPos Buy(classCode, secCode, -lastPos, 'CloseAll') else mes = secCode..'; Нажато: Закрыть. Нет позиций для закрытия!' end elseif par1 == 3 and par2 == 1 then if lastPos < 0 then mes = secCode..'; Нажато: Купить-, '..-lastPos BuyBid(classCode, secCode, -lastPos, 'CloseShort') elseif lastPos == 0 then BuyBid(classCode, secCode, workSize, 'OpenLong') mes = secCode..'; Нажато: Купить-, '..workSize else mes = secCode..'; Нажато: Купить-. Мы в лонгах, не покупаем!' end elseif par1 == 3 and par2 == 2 then if lastPos > 0 then SellOffer(classCode, secCode, lastPos, 'CloseLong') mes = secCode..'; Нажато: Продать+, '..lastPos elseif lastPos == 0 then SellOffer(classCode, secCode, workSize, 'OpenShort') mes = secCode..'; Нажато: Продать+, '..workSize else mes = secCode..'; Нажато: Продать+. Мы в шортах, не продаем!' end elseif par1 == 3 and par2 == 3 then mes = secCode..'; Нажато: Снять все заявки!' 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 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(price), 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 = 'Ошибка: '..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 = 'Ошибка: '..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 = 'Ошибка: '..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 = 'Ошибка: '..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 = 'Ошибка: '..res message(mes,3); io_log(mes); end end end end end -- function HandleBS() local t = tblH.t_id AddColumn(t, 1, 'Бумага', true,QTABLE_CACHED_STRING_TYPE,12) AddColumn(t, 2, 'ТЧП', true,QTABLE_STRING_TYPE,12) AddColumn(t, 3, 'Цена последняя', 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, 'Нет Цены') --Ожидание local li=InsertRow(t, -1) SetCell(t, li, 1, 'Купить') SetCell(t, li, 2, 'Продать') SetCell(t, li, 3, 'Закрыть') local li=InsertRow(t, -1) SetCell(t, li, 1, 'Купить -') SetCell(t, li, 2, 'Продать +') SetCell(t, li, 3, 'Снять все') 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, "Ошибка записи "..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 = 'Закрыт 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 |