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

  • обсудить на форуме:
  • QUIK
★7
ВНИМАНИЕ! КОММЕНТАРИИ ПЕРВОГО УРОВНЯ В ВОПРОСАХ УПОРЯДОЧИВАЮТСЯ ПО ЧИСЛУ ПЛЮСИКОВ, А НЕ ПО ВРЕМЕНИ ПУБЛИКАЦИИ.

— == 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

YouScriptor.com (вайб-хайринг), Спасибо, попробую!
avatar
AlexGood, 21:00 Не поленись рассказать о результатах попробования.
avatar
Rostislav Kudryashov, не работает!
avatar
AlexGood, 21:37 Чего ж ты хотел от бесплатного?
avatar
AlexGood, 
avatar
YouScriptor.com (вайб-хайринг), поставил код класса TQCB (у меня для облиги нужно), тикер RU000… 1 лот и при попытке запуска пишет: Syntax error while compiling (адрес где на компе этот скрипт) unexpected symbol near '<\151>'
avatar
AlexGood, кодировку проверьте
YouScriptor.com (вайб-хайринг), это как?
avatar
AlexGood, 

Это из-за «красивых» символов, которые попали при копипасте: в коде вместо обычных дефисов - оказались длинные тире (в cp1251 это байт 151), и Lua ругается: unexpected symbol near '<\151>'.

Что сделать быстро:

  1. Открой файл в обычном редакторе (Notepad++ / VS Code).

  2. Замените все “косые кавычки” и длинные тире на обычные ASCII символы:

    • и -

    • « »"

  3. Сохраните файл как UTF-8 (без BOM) или ANSI (Windows-1251).

  4. Убедитесь, что комментарии начинаются ровно -- (две короткие черты), не .

Ниже — «чистая» 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.

  • Убедитесь, что все комментарии начинаются --, а не каким-то похожим символом.

Если хочешь, добавлю «бережный» режим: переставлять только если мы перестали быть лучшими, чтобы не терять очередь.

   
YouScriptor.com (вайб-хайринг), заменил на обновленный код, теперь скрипт просто не запускается, ошибок не пишет!
avatar
AlexGood, ну дальше сами уже без меня )
YouScriptor.com (вайб-хайринг), 
avatar
chatgpt попроси написать
У меня данная процедура состоит из 2 частей:
1. постоянная проверка списка активных и нереализованных ордеров или их частей, т.е. контроль нереализованного остатка, в таблице Заявки. Признак — ненулевой balance в параметрах и соответствующий bit.test() по id заявки.
2. Поскольку бот — это цикл с интервалом времени sleep(), то проверка п.1 происходит каждый раз после этого интервала.
3. Если bit.test() показал, что есть нереализованный остаток, то эта заявка сначала копируется в отдельную внешнюю БД (для чего — это отдельный разговор),
4. Эта заявка с новым ID и новым объемом (в размере нереализованного остатка старой Заявки) получает данные цены из Таблицы Параметров Торгов (параметры BID, OFFER, LAST — соответствующие цены в данный момент) и перевыставляется с учетом нужного изменения (± от нужного параметра цены) и с учетом шага цены для данного инструмента.

Работоспособность проверена лично. Зуб даю.))

Весь алгоритм (без кода lua) представлен в посте в моем СЛ-блоге. Блог небольшой, можно найти быстро «Коллбэки своими руками».
avatar
В Quik Lua состояние стакана запрашивается функцией getQuoteLevel2().
Эту функцию надо вставить в обработчик изменения стакана OnQuote(). Это функция обратного вызова.
И уповать, что послав цену на один тик сдвинутую от лучшей цены стакана, эта заявка придёт на биржу с тем же сдвигом от текущей на момент прихода лучшей цены стакана.
При интенсивных торгах никто не гарантирует, что на это хватит скорости интернета и поворотливости сервера брокера.
При этом нелишне отследить, что случилось с предыдушей заявкой.

Всё это есть  в YouScriptor.com (вайб-хайринг)  Вчера в 20:24
Только скинуто в ленту неаккуратно. И без внутриблочных отступов почти нечитаемо.
Чтобы заработало, надо понимать, что к чему.
avatar
Может я  не понял вопрос, но вроде это базовый функционал в Квике
Заявки тейк-профит именно так и работают, постоянно переставляясь все выше по тренду
 
avatar
Viacheslav Ivanenkov, никуда тейки сами не переставляются!
avatar
Тейк сам по себе конечно не переставляется так как это всего лишь условие порожденя лимитки или рыночной заявки


Здесь не написано что происходит при повышении цены
А происходит следущее — от последней максимальной цены сделки тейк следит куда идет цена, если вниз — то при достижении отступа срабатывает условие(как написано в справке)
А вот если цена идет вверх то тейк продолжает следить и постоянно увеличивает значение  «последней максимальной цены» постоянно сдвигаясь вверх следом за ценой последней сделки, считайте что условие срабатывания тейка постоянно пересчитывается в сторону увеличения

И сработает тейк только когда тренд изменится  и цена начнет снижаться

Не знаю что делает упомянутый скрипт но по описанию похоже что то же самое что и сам тейк, иными словами — ничего 
avatar
 Я думал пост будет, Друзья, у кого нить есть скрипт для квик, который делает 30% годовых?! А тут скучно(
avatar

Только зарегистрированные и авторизованные пользователи могут оставлять ответы.

Залогиниться

Зарегистрироваться

теги блога AlexGood

....все тэги



UPDONW
Новый дизайн