Друзья, у кого-нибудь есть скрипт для КВИК, который переставляет заявку трейдера …

Друзья, у кого-нибудь есть скрипт для КВИК, который переставляет заявку трейдера всегда на 1 тик выше лучшего бида?😏 спецраздел: +2 — == QUICk/QLUA: авто-перестановка лимитной покупки на +1 тик от лучшего бида == — ————————- — CONFIG: настроить под себя — ————————- local CONFIG = { CLASS_CODE = «TQBR», — класс инструмента (акции T+ обычно TQBR) SEC_CODE = «GAZP», — тикер ACCOUNT = «L01-00000F00»,— торговый счет (trdaccid для T+) CLIENT_CODE = "", — клиентский код (может быть пустым) QUANTITY = 100, — лот/кол-во BROKERREF = «autobid+1», — пометка брокеру (необязательно) ALLOW_CROSS = false, — true чтобы разрешить пересечение спреда (мгновенное исполнение) MIN_REPLACE_MS= 800, — не чаще чем раз в N мс (анти-флуд) PRICE_ROUND = 6 — точность округления цены } — ————————- — Внутренние переменные — ————————- local last_action_ms = 0 local current_order_num = nil — Биржевой номер активной заявки local current_price = nil — Текущая цена активной заявки local price_step = nil — Шаг цены инструмента local best_bid, best_ask = nil, nil local running = true — ————————- — Утилиты — ————————- local function now_ms() return os.time() * 1000 + (getInfoParam(«LOCAL_TIME_MCS») ~= "" and math.floor(tonumber(getInfoParam(«LOCAL_TIME_MCS»))/1000)%1000 or 0) end local function to_num(x) if x == nil then return nil end local n = tonumber(tostring(x):gsub(",", ".")) return n end local function round_price(p) if not p then return nil end local scale = 10^CONFIG.PRICE_ROUND return math.floor(p*scale + 0.5)/scale end local function fetch_price_step() — В QUIK параметр шага цены: «SEC_PRICE_STEP» local p = getParamEx(CONFIG.CLASS_CODE, CONFIG.SEC_CODE, «SEC_PRICE_STEP») if p and p.param_type ~= 0 and p.param_value ~= "" then return to_num(p.param_value) end — запасной путь (иногда брокеры публикуют STEPPRICe/PRICESTEP) local p2 = getParamEx(CONFIG.CLASS_CODE, CONFIG.SEC_CODE, «PRICESTEP») if p2 and p2.param_type ~= 0 and p2.param_value ~= "" then return to_num(p2.param_value) end message(«Не удалось определить SEC_PRICE_STEP — проверьте настройки инструмента», 3) return nil end local function read_l2_best() local book = getQuoteLevel2(CONFIG.CLASS_CODE, CONFIG.SEC_CODE) if not book then return nil, nil end local bid = nil if book.bid_count and book.bid_count > 0 then bid = to_num(book.bid[1].price) end local ask = nil if book.offer_count and book.offer_count > 0 then ask = to_num(book.offer[1].price) end return bid, ask end local function desired_price() if not best_bid or not price_step then return nil end local p = best_bid + price_step if not CONFIG.ALLOW_CROSS and best_ask and p >= best_ask then — Чуть ниже оффера, чтобы не сделать рыночную покупку if best_ask — price_step > 0 then p = best_ask — price_step else — если шаг не позволяет опуститься — остаёмся на бест бид + шаг (может исполниться) end end return round_price(p) end local function can_replace() return (now_ms() — last_action_ms) >= CONFIG.MIN_REPLACE_MS end local function kill_current_order() if not current_order_num then return end local t = { [«TRANS_ID»] = tostring( os.time()… «01» ), [«ACTION»] = «KILL_ORDER», [«CLASSCODE»] = CONFIG.CLASS_CODE, [«SECCODE»] = CONFIG.SEC_CODE, [«ORDER_KEY»] = tostring(current_order_num) } sendTransaction(t) last_action_ms = now_ms() end local function place_order(price) local t = { [«TRANS_ID»] = tostring( os.time()… «02» ), [«ACTION»] = «NEW_ORDER», [«CLASSCODE»] = CONFIG.CLASS_CODE, [«SECCODE»] = CONFIG.SEC_CODE, [«ACCOUNT»] = CONFIG.ACCOUNT, [«CLIENT_CODE»]= CONFIG.CLIENT_CODE, [«OPERATION»] = «B», — Покупка [«PRICE»] = string.format("%."..CONFIG.PRICE_ROUND..«f», price), [«QUANTITY»] = tostring(CONFIG.QUANTITY), [«TYPE»] = «L», — Лимитка [«BROKERREF»] = CONFIG.BROKERREF } sendTransaction(t) last_action_ms = now_ms() end local function sync_order() if not can_replace() then return end local want = desired_price() if not want then return end if current_price and math.abs(current_price — want) < 1e-10 then return — уже на нужной цене end — Убираем старую и ставим новую if current_order_num then kill_current_order() end place_order(want) end — ————————- — Callbacks — ————————- function OnInit() price_step = fetch_price_step() best_bid, best_ask = read_l2_best() message(string.format(«Автобид запущен: %s/%s, шаг=%.10f, cross=%s», CONFIG.CLASS_CODE, CONFIG.SEC_CODE, price_step or -1, tostring(CONFIG.ALLOW_CROSS)), 1) end function OnQuote(class_code, sec_code) if not running then return end if class_code ~= CONFIG.CLASS_CODE or sec_code ~= CONFIG.SEC_CODE then return end best_bid, best_ask = read_l2_best() sync_order() end function OnOrder(order) if not running then return end if order.class_code ~= CONFIG.CLASS_CODE or order.sec_code ~= CONFIG.SEC_CODE then return end if order.trans_id and order.flags then — flags битовый; 0x1=покупка; 0x2=продажа; 0x4=активна и т.д. — Отслеживаем размещение и изменение своей лимитки if order.brokerref == CONFIG.BROKERREF and order.account == CONFIG.ACCOUNT then — Сохраняем актуальную заявку if bit and bit.band(order.flags, 0x4) ~= 0 then current_order_num = order.order_num current_price = to_num(order.price) else — Заявка снята/исполнена if current_order_num == order.order_num then current_order_num = nil current_price = nil end end end end end function OnTrade(trade) — Если частично/полностью исполнилась — в зависимости от вашей логики — можно сразу выставлять заново оставшийся объём на +тик end function OnStop(sign) running = false — По желанию можно снять остаток: — if current_order_num then kill_current_order() end message(«Автобид остановлен», 1) end +1 AlexGood, Это из-за «красивых» символов, которые попали при копипасте: в коде вместо обычных дефисов — оказались длинные тире — (в cp1251 это байт 151), и Lua ругается: unexpected symbol near '<\151>'. Что сделать быстро: Открой файл в обычном редакторе (Notepad++ / VS Code). Замените все “косые кавычки” и длинные тире на обычные ASCII символы: — и – → — Сохраните файл как UTF-8 (без BOM) или ANSI (Windows-1251). Убедитесь, что комментарии начинаются ровно — (две короткие черты), не —. Ниже — «чистая» ASCII-версия скрипта (минимум зависимостей), под TQCB/облигации. Скопируйте целиком; в CONFIG поставьте ваш CLASS_CODE=«TQCB» и SEC_CODE=«RU000…». — QUIK/QLUA: держим лимитную покупку на 1 тик выше лучшего бида — ВНИМАНИЕ: файл должен быть в чистом ASCII/UTF-8 без BOM. Все дефисы обычные "-". local CONFIG = { CLASS_CODE = "TQCB", — для облигаций MOEX T+ обычно TQCB SEC_CODE = "RU0000000000", — ваш тикер ACCOUNT = "L01-00000F00", — trdaccid для T+ CLIENT_CODE = "", — если требуется брокером QUANTITY = 1, — размер заявки (лот) BROKERREF = "autobid+1", ALLOW_CROSS = false, — не пересекаем спред MIN_REPLACE_MS = 800, — антифлуд PRICE_ROUND = 6 — точность цены (под облиги можно 4..6) } — state local last_action_ms = 0 local current_order_num = nil local current_price = nil local price_step = nil local best_bid, best_ask = nil, nil local running = true — utils local function now_ms() local mcs = getInfoParam("LOCAL_TIME_MCS") local ms = 0 if mcs ~= "" then ms = math.floor(tonumber(mcs) / 1000) % 1000 end return os.time() * 1000 + ms end local function to_num(x) if x == nil then return nil end local s = tostring(x):gsub(",", ".") return tonumber(s) end local function round_price(p) if not p then return nil end local scale = 10 ^ CONFIG.PRICE_ROUND return math.floor(p * scale + 0.5) / scale end local function fetch_price_step() local p = getParamEx(CONFIG.CLASS_CODE, CONFIG.SEC_CODE, "SEC_PRICE_STEP") if p and p.param_value ~= "" then return to_num(p.param_value) end local p2 = getParamEx(CONFIG.CLASS_CODE, CONFIG.SEC_CODE, "PRICESTEP") if p2 and p2.param_value ~= "" then return to_num(p2.param_value) end message("SEC_PRICE_STEP not found. Check instrument params.", 3) return nil end local function read_l2_best() local book = getQuoteLevel2(CONFIG.CLASS_CODE, CONFIG.SEC_CODE) if not book then return nil, nil end local bid = nil if book.bid_count and book.bid_count > 0 then bid = to_num(book.bid[1].price) end local ask = nil if book.offer_count and book.offer_count > 0 then ask = to_num(book.offer[1].price) end return bid, ask end local function desired_price() if not best_bid or not price_step then return nil end local p = best_bid + price_step if not CONFIG.ALLOW_CROSS and best_ask and p >= best_ask then if best_ask — price_step > 0 then p = best_ask — price_step end end return round_price(p) end local function can_replace() return (now_ms() — last_action_ms) >= CONFIG.MIN_REPLACE_MS end local function kill_current_order() if not current_order_num then return end local t = { TRANS_ID = tostring(os.time() .. "01"), ACTION = "KILL_ORDER", CLASSCODE = CONFIG.CLASS_CODE, SECCODE = CONFIG.SEC_CODE, ORDER_KEY = tostring(current_order_num) } sendTransaction(t) last_action_ms = now_ms() end local function place_order(price) local t = { TRANS_ID = tostring(os.time() .. "02"), ACTION = "NEW_ORDER", CLASSCODE = CONFIG.CLASS_CODE, SECCODE = CONFIG.SEC_CODE, ACCOUNT = CONFIG.ACCOUNT, CLIENT_CODE = CONFIG.CLIENT_CODE, OPERATION = "B", PRICE = string.format("%." .. CONFIG.PRICE_ROUND .. "f", price), QUANTITY = tostring(CONFIG.QUANTITY), TYPE = "L", BROKERREF = CONFIG.BROKERREF } sendTransaction(t) last_action_ms = now_ms() end local function sync_order() if not can_replace() then return end local want = desired_price() if not want then return end if current_price and math.abs(current_price — want) < 1e-10 then return end if current_order_num then kill_current_order() end place_order(want) end — callbacks function OnInit() price_step = fetch_price_step() best_bid, best_ask = read_l2_best() message("AutoBid started " .. CONFIG.CLASS_CODE .. "/" .. CONFIG.SEC_CODE, 1) end function OnQuote(class_code, sec_code) if not running then return end if class_code ~= CONFIG.CLASS_CODE or sec_code ~= CONFIG.SEC_CODE then return end best_bid, best_ask = read_l2_best() sync_order() end function OnOrder(order) if not running then return end if order.class_code ~= CONFIG.CLASS_CODE or order.sec_code ~= CONFIG.SEC_CODE then return end if order.brokerref == CONFIG.BROKERREF and order.account == CONFIG.ACCOUNT then if order.flags and (order.flags % 8) >= 4 then current_order_num = order.order_num current_price = to_num(order.price) else if current_order_num == order.order_num then current_order_num = nil current_price = nil end end end end function OnStop(sign) running = false message("AutoBid stopped", 1) end Если снова появится такая ошибка, быстро проверить: В Notepad++: Поиск → Заменить → Включить регулярные выражения → Найти: [^\x00-\x7F] → Заменить на пусто → «Заменить все». Это уберет не-ASCII. Убедитесь, что все комментарии начинаются —, а не каким-то похожим символом. Если хочешь, добавлю «бережный» режим: переставлять только если мы перестали быть лучшими, чтобы не терять очередь. Source: https://smart-lab.ru/vopros/1222866.php