— == 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 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 (вайб-хайринг), поставил код класса TQCB (у меня для облиги нужно), тикер RU000… 1 лот и при попытке запуска пишет: Syntax error while compiling (адрес где на компе этот скрипт) unexpected symbol near '<\151>'
Это из-за «красивых» символов, которые попали при копипасте: в коде вместо обычных дефисов - оказались длинные тире — (в 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.
Убедитесь, что все комментарии начинаются --, а не каким-то похожим символом.
Если хочешь, добавлю «бережный» режим: переставлять только если мы перестали быть лучшими, чтобы не терять очередь.
У меня данная процедура состоит из 2 частей:
1. постоянная проверка списка активных и нереализованных ордеров или их частей, т.е. контроль нереализованного остатка, в таблице Заявки. Признак — ненулевой balance в параметрах и соответствующий bit.test() по id заявки.
2. Поскольку бот — это цикл с интервалом времени sleep(), то проверка п.1 происходит каждый раз после этого интервала.
3. Если bit.test() показал, что есть нереализованный остаток, то эта заявка сначала копируется в отдельную внешнюю БД (для чего — это отдельный разговор),
4. Эта заявка с новым ID и новым объемом (в размере нереализованного остатка старой Заявки) получает данные цены из Таблицы Параметров Торгов (параметры BID, OFFER, LAST — соответствующие цены в данный момент) и перевыставляется с учетом нужного изменения (± от нужного параметра цены) и с учетом шага цены для данного инструмента.
Работоспособность проверена лично. Зуб даю.))
Весь алгоритм (без кода lua) представлен в посте в моем СЛ-блоге. Блог небольшой, можно найти быстро «Коллбэки своими руками».
В Quik Lua состояние стакана запрашивается функцией getQuoteLevel2().
Эту функцию надо вставить в обработчик изменения стакана OnQuote(). Это функция обратного вызова.
И уповать, что послав цену на один тик сдвинутую от лучшей цены стакана, эта заявка придёт на биржу с тем же сдвигом от текущей на момент прихода лучшей цены стакана.
При интенсивных торгах никто не гарантирует, что на это хватит скорости интернета и поворотливости сервера брокера.
При этом нелишне отследить, что случилось с предыдушей заявкой.
Всё это есть в YouScriptor.com (вайб-хайринг) Вчера в 20:24
Только скинуто в ленту неаккуратно. И без внутриблочных отступов почти нечитаемо.
Чтобы заработало, надо понимать, что к чему.
Тейк сам по себе конечно не переставляется так как это всего лишь условие порожденя лимитки или рыночной заявки
Здесь не написано что происходит при повышении цены
А происходит следущее — от последней максимальной цены сделки тейк следит куда идет цена, если вниз — то при достижении отступа срабатывает условие(как написано в справке)
А вот если цена идет вверх то тейк продолжает следить и постоянно увеличивает значение «последней максимальной цены» постоянно сдвигаясь вверх следом за ценой последней сделки, считайте что условие срабатывания тейка постоянно пересчитывается в сторону увеличения
И сработает тейк только когда тренд изменится и цена начнет снижаться
Не знаю что делает упомянутый скрипт но по описанию похоже что то же самое что и сам тейк, иными словами — ничего
— == 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
Это из-за «красивых» символов, которые попали при копипасте: в коде вместо обычных дефисов
-оказались длинные тире—(в 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.Убедитесь, что все комментарии начинаются
--, а не каким-то похожим символом.Если хочешь, добавлю «бережный» режим: переставлять только если мы перестали быть лучшими, чтобы не терять очередь.
1. постоянная проверка списка активных и нереализованных ордеров или их частей, т.е. контроль нереализованного остатка, в таблице Заявки. Признак — ненулевой balance в параметрах и соответствующий bit.test() по id заявки.
2. Поскольку бот — это цикл с интервалом времени sleep(), то проверка п.1 происходит каждый раз после этого интервала.
3. Если bit.test() показал, что есть нереализованный остаток, то эта заявка сначала копируется в отдельную внешнюю БД (для чего — это отдельный разговор),
4. Эта заявка с новым ID и новым объемом (в размере нереализованного остатка старой Заявки) получает данные цены из Таблицы Параметров Торгов (параметры BID, OFFER, LAST — соответствующие цены в данный момент) и перевыставляется с учетом нужного изменения (± от нужного параметра цены) и с учетом шага цены для данного инструмента.
Работоспособность проверена лично. Зуб даю.))
Весь алгоритм (без кода lua) представлен в посте в моем СЛ-блоге. Блог небольшой, можно найти быстро «Коллбэки своими руками».
Эту функцию надо вставить в обработчик изменения стакана OnQuote(). Это функция обратного вызова.
И уповать, что послав цену на один тик сдвинутую от лучшей цены стакана, эта заявка придёт на биржу с тем же сдвигом от текущей на момент прихода лучшей цены стакана.
При интенсивных торгах никто не гарантирует, что на это хватит скорости интернета и поворотливости сервера брокера.
При этом нелишне отследить, что случилось с предыдушей заявкой.
Всё это есть в YouScriptor.com (вайб-хайринг) Вчера в 20:24
Только скинуто в ленту неаккуратно. И без внутриблочных отступов почти нечитаемо.
Чтобы заработало, надо понимать, что к чему.
Заявки тейк-профит именно так и работают, постоянно переставляясь все выше по тренду
Здесь не написано что происходит при повышении цены
А происходит следущее — от последней максимальной цены сделки тейк следит куда идет цена, если вниз — то при достижении отступа срабатывает условие(как написано в справке)
А вот если цена идет вверх то тейк продолжает следить и постоянно увеличивает значение «последней максимальной цены» постоянно сдвигаясь вверх следом за ценой последней сделки, считайте что условие срабатывания тейка постоянно пересчитывается в сторону увеличения
И сработает тейк только когда тренд изменится и цена начнет снижаться
Не знаю что делает упомянутый скрипт но по описанию похоже что то же самое что и сам тейк, иными словами — ничего
Только зарегистрированные и авторизованные пользователи могут оставлять ответы.
Залогиниться
Зарегистрироваться