Имеет практический смысл создавать отдельных роботов для акций, фьючерсов, опционов, валюты, облигаций. ---------------------------- Можно создать отдельных роботов для ликвидных и неликвидных акций. ------------------------------ Для каждого такого робота создается своя задача или несколько задач. В итоге создается библиотека задач. ----------------------- Особенность таких задач в том, что в них не надо реализовывать механизм работы с биржей или брокером. Это все делает основной робот nkbot. Он и заявку отправит и стоп поставит, если надо.
Структура моего робота
Пользователь
Сообщений: Регистрация: 30.01.2015
24.11.2025 11:18:21
В данной теме рассказываю, как построен мой торговый робот.
Полагаю, что тема будет интересна не только начинающим писателям роботов,
так как излагаю свои идеи, которые обладают определенной новизной .
----------------------------
Структура робота организована в виде сети роботов типа “звезда”.
Каждый робот – это отдельный поток или процесс ОС Windows.
------------------------------
В центре звезды находится главный робот nkbot, который обрабатывает события колбеков и таймера и раздает задания другим роботам.
События организованы в виде очереди. Если событий нет в течении заданного интервала, то робот выполняет задание по таймеру.
---------------------------
Все остальные роботы работают с заданной для каждого робота группой инструментов
и выполняют свои задачи по команде nkbot, либо по истечению заданного интервала времени.
---------------------------
Каждый робот работает в своем потоке OS Windows, либо в процессе терминала QUIK и имеет доступ к библиотеке QLua, либо в изолированном потоке(процессе) OS
Роботы в терминале запускаются как скрипты терминала QUIK.
----------------------------
Связь робота nkbot с каждым роботом сети выполняется через очередь команд в общей памяти.
Список работающих роботов создается в файле инициализации nkbot_ini.lua.
Задачи для роботов создаются в отдельных файлах в виде функций и загружаются в робота во время запуска скрипта по заданному списку задач для каждого робота.
--------------------------
Несколько примеров реализации отдельных элементов данной структуры.
Все роботы сети, кроме nkbot, имеют одинаковую структуру и реализуются одним скриптом.
Имя робота состоит из “nkbot_” и далее идентификатор робота.
Например, nkbot_B.lua, nkbot_C.lua два робота B и C
Файл nk_bot_B.lua
Код
Ts={SBER={int={1,2,5,10,20},q=true},
GAZP={int={2,5},q=true}, LKOH={int={5},q=true}}
--инструменты, которыми торгует робот , интервалы свечей и флаг
получения стакана
list_task="task1,task2" -- задачи, которые
быдет исполнять робот
nkLog=true; -- -включить вывод в лог файл
----------------не трогать---------------
minfo =
debug.getinfo(1, "S").source:sub(2); path =
minfo:match("(.*[/\\])") or "."
dofile(path.."stream.lua")
Файл nk_bot_С.lua
Код
Ts={SiZ5={int={5}}, RIZ5={int={5,10},},SRZ5={int={30}}}
--инструменты и интервалы свечей
list_task="task3,task4" -- список задач
nkLog=true;
----------------не трогать---------------
minfo =
debug.getinfo(1, "S").source:sub(2); path =
minfo:match("(.*[/\\])") or "."
dofile(path.."stream.lua")
В качестве финального варианта выкладываю скрипт подписки без колбеков.
Код
--Пример асинхронного запроса свечей--результат в массиве ds для каждого инструмента
----------------------
name="nk_bot"
fnlog="D:/"..name..".log"; nkLog=io.open(fnlog,"w")
Tclas={}
Tclas.QJSIM={SBER={int={1,2,5,10,20},ds={}}, GAZP={int={2,5},ds={}}, LKOH={int={5},ds={}}}
Tclas.SPBFUT={SiZ5={int={5},ds={}}, RIZ5={int={5,10},ds={}},SRZ5={int={30},ds={}}}
local tim=os.clock()
------------------------
function main()
run=true;
local x=0; for c,tc in pairs(Tclas) do for s,ts in pairs(tc) do x=x+1 end end MaxDS=x;
while run do
if MaxDS then
for c,tc in pairs(Tclas) do
for s,ts in pairs(tc) do
local ts=tc[s]; local int=ts.int; local ds=ts.ds;local N=#int; local M=#ds;
if N~=M then local j=0;
while N>j do j=j+1;
if ds[j]==nil then local x=CreateDataSource(c,s, int[j]);
if x and x:Size()>0 then local ti=math.tointeger(1000*(os.clock()-tim)//1);
ds[j]=x; nkLog:write("time(ms)="..tostring(ti)..","..c..","..s..",j="..j..",int="..int[j]..",size="..ds[j]:Size().."\n"); nkLog:flush();
end
end
end
M=#ds; if N==M then MaxDS=MaxDS-1; nkLog:write(s..",подписка завершена\n"); nkLog:flush(); end
end
end
end
if MaxDS==0 then nkLog:write("блокируем блок подписки\n"); nkLog:flush(); MaxDS=nil end
end
-- Выполнение заданий скрипта --
sleep (10)
end
end
function OnStop(signal) run = false return 1000 end
после завершения подписки в main будет исполнятся из кода подписки лишь один оператор if. ------------------------------ Недостаток этого варианта по сравнению с первым тот, что в нем тратится время main на неисполненные подписки, если данный инструмент не торгуется. Во втором варианте тратится время основного потока QUIK на подобные подписки. -------------------------- Оптимальным вариантом будет решение, которое объединяет первый третий вариант. -------------------------------- Именно такое решение я и использую в настоящее время.
Асинхронная подписка на свечи
Пользователь
Сообщений: Регистрация: 30.01.2015
21.11.2025 21:50:39
поправил немного:
Код
function OnParam(c,s)
if MaxDS then
for c,tc in pairs(Tclas) do
for s,ts in pairs(tc) do
local ts=tc[s]; local int=ts.int; local ds=ts.ds;local N=#int; local M=#ds;
if N~=M then local j=0;
while N>j do j=j+1;
if ds[j]==nil then local x=CreateDataSource(c,s, int[j]);
if x:Size()>0 then local ti=math.tointeger(1000*(os.clock()-tim)//1);
ds[j]=x; nkLog:write("time(ms)="..tostring(ti)..","..c..","..s..",j="..j..",int="..int[j]..",size="..ds[j]:Size().."\n"); nkLog:flush();
end
end
end
M=#ds; if N==M then MaxDS=MaxDS-1; nkLog:write(s..",подписка завершена\n"); nkLog:flush(); end
end
end
end
if MaxDS==0 then nkLog:write("блокируем OnParam\n"); nkLog:flush(); MaxDS=nil end
end
end
Асинхронная подписка на свечи
Пользователь
Сообщений: Регистрация: 30.01.2015
21.11.2025 21:42:20
Поступило два вопроса. 1) Если инструмент очень редко изменяется в ТТП, но кому-то надо срочно что-то считать ( не представляю что надо считать по этому инструменту) . Решаем эту проблему. -------------------------- 2) Этот код, хоть и на 4 мкс, но будет грузить основной поток после того, как подписка закончится. Решает и эту проблему, ----------------------------------- Вот вариант скрипта, в котором этих проблем нет:
Код
--Пример асинхронного запроса свечей--
--результат в массиве ds для каждого инструмента
Tclas={}
Tclas.QJSIM={SBER={int={1,2,5,10,20},ds={}}, GAZP={int={2,5},ds={}}, LKOH={int={5},ds={}}}
Tclas.SPBFUT={SiZ5={int={5},ds={}}, RIZ5={int={5,10},ds={}},SRZ5={int={30},ds={}}}
local tim=os.clock()
------------------------
RUN = true
function main()
local fDS=true;
while RUN do
-- Выполнение заданий скрипта --
sleep (10)
end
end
---------------------------------]
function OnParam(c,s)
if MaxDS then
for c,tc in pairs(Tclas) do
for s,ts in pairs(tc) do
local ts=tc[s]; local int=ts.int; local ds=ts.ds;local N=#int; local M=#ds;
if N~=M then local j=0;
while N>j do j=j+1;
if ds[j]==nil then local x=CreateDataSource(c,s, int[j]);
if x:Size()>0 then local ti=math.tointeger(1000*(os.clock()-tim)//1);
ds[j]=x; nkLog:write("time(ms)="..tostring(ti)..","..c..","..s..",j="..j..",int="..int[j]..",size="..ds[j]:Size().."\n");nkLog:flush();
end
end
end
M=#ds; if N==M then MaxDS=MaxDS-1; nkLog:write(s..",подписка завершена\n"); nkLog:flush(); end
end
end
end
end
if MaxDS==0 then nkLog:write("блокируем OnParam\n"); nkLog:flush(); MaxDS=nil end
end
function OnStop(signal) RUN = false return 5000 end
function OnInit(p) -- инициализация функции main
local p=string.reverse(p); local n,m=string.find(p,"\\");
local pS=string.reverse(string.sub(p,n)); name=string.reverse(string.sub(p,5,n-1)) ;
package.cpath =package.cpath..";"..pS.."?.dll;"
package.path =package.path..";"..pS.."?.lua;"..pS.."?.luac;"
fnlog=pS..name.."_nk.log"; nkLog=io.open(fnlog,"w")
local x=0; for c,tc in pairs(Tclas) do for s,ts in pairs(tc) do x=x+1 end end MaxDS=x;
end
--------------------------- а это результат его работы:
Э... Возникает вопрос - а когда подписка закончена, этот код что будет делать на постоянные вызовы OnParam? Да и нагрузка на сам колбек основного потока, хоть и небольшая, но есть. Плюс, если инструмент малоликвиден, то подписка на данные когда произойдет? Иногда ведь надо получить данные, что-то рассчитать и закрыть поток. И надо это сейчас, а не когда через часы будет изменение ТТТ.
Когда подписка закончена, Ничего не делает. Я Выше уже приводил затраты времени. На основной поток это 4 мкс. Ну относительно нагрузки на основной поток в 4 мкс это прикольно. -------------------------- Если надо и эти 4 мкс убрать, то надо делать как у меня в настоящее время. ---------------------- Этот код находится в main. А колбек Onparam как и все другие лишь отсылает событие в очередь. ---------------------- Я не стал приводить этот вариант, так как я использую механизм событий, а его посетители этого сайта не поймут и не реализуют . ------------------ Поэтому привел этот вариант ему уже лет пятнадцать. ======================== Относительно про часы изменения ТТП Вы сильно ошибаетесь. ТТП меняется на любой чих по инструменту. Т е не только изменение сделок но и изменение очереди заявок. -------------------- Прикольно, Но если ТТП у Вас часами не меняется по инструменту то что Вы будете считать? Тогда у вас кроме истории часовой давности ничего нет, ее вы уже получили час назад. Я любую историю сделок с задержкой 15 инут (бесплатно) получаю с биржи. Для этого QUIK не нужен вообще.
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 30.01.2015
21.11.2025 20:52:46
Вы опять ушли от ответ. Повторяю вопрос Где в документации указано: Цитата из ваших ля...ля: Из справки: "Функцию CreateDataSource можно использовать только внутри функций main() и callback." Ау где Вы это прочитали?
Скрипт правильно ли написан
Пользователь
Сообщений: Регистрация: 30.01.2015
21.11.2025 19:02:52
Прикольно, А компьютера у Вас нет?
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 30.01.2015
21.11.2025 19:01:07
CreateDataSource
я нашел лишь это:
Код
Функция предназначена для создания таблицы Lua и позволяет работать со свечками, полученными с сервера QUIK,
а также реагировать на их изменение.Формат вызова:TABLE data_source,
STRING error_desc CreateDataSource (STRING class_code, STRING sec_code, NUMBER interval,
[, STRING param])Параметры:class_code – код класса,sec_code – код инструмента,interval – интервал запрашиваемого графика,param – необязательный параметр.
Если параметр не задан,
то заказываются данные на основании таблицы обезличенных сделок, если задан –
данные по этому параметру.
Функция возвращает таблицу data_source в случае успешного завершения.
Если указан неверный код класса или параметр, то возвращается «nil».
При этом error_desc содержит описание ошибки.Список констант для передачи в параметр interval :
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 30.01.2015
21.11.2025 18:58:15
Цитата
VPM написал: Из справки: "Функцию CreateDataSource можно использовать только внутри функций main() и callback."
Но по моему в OnInit (инициализация функции main ) она не работает? Или?
Дайте ссылку на страницу справки. Вы зачем свои домыслы здесь пишите? Может сначала проверите, что зря интернет засорять.
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 30.01.2015
21.11.2025 15:56:00
Код
-Пример асинхронного запроса свечей--
--результат в массиве ds для каждого инструмента
Tclas={}
Tclas.QJSIM={SBER={int={1,2,5,10,20},ds={}}, GAZP={int={2,5},ds={}}, LKOH={int={5},ds={}}}
Tclas.SPBFUT={SiZ5={int={5},ds={}}, RIZ5={int={5,10},ds={}},SRZ5={int={30},ds={}}}
local tim=os.clock()
function OnParam(c,s)
local tc=Tclas[c]
if tc then local ts=tc[s];
if ts then local ts=tc[s]; local int=ts.int; local ds=ts.ds;local N=#int; local M=#ds;
if N~=M then local j=0;
while N>j do j=j+1;
if ds[j]==nil then local x=CreateDataSource(c,s, int[j]);
if x:Size()>0 then local ti=math.tointeger(1000*(os.clock()-tim)//1);
ds[j]=x; nkLog:write("time(ms)="..tostring(ti)..","..c..","..s..",j="..j..",int="..int[j]..",size="..ds[j]:Size().."\n"); nkLog:flush();
end
end
end
M=#ds; if N==M then nkLog:write(s..",подписка завершена\n"); nkLog:flush(); end
end
end
end
end
RUN = truefunction main()
while RUN do
-- Выполнение заданий скрипта --
sleep (10)
end
end
function OnStop(signal) RUN = false return 5000 end
function OnInit(p)
local p=string.reverse(p); local n,m=string.find(p,"\\");
local pS=string.reverse(string.sub(p,n)); name=string.reverse(string.sub(p,5,n-1)) ;
package.cpath =package.cpath..";"..pS.."?.dll;"
package.path =package.path..";"..pS.."?.lua;"..pS.."?.luac;"
fnlog=pS..name.."_nk.log"; nkLog=io.open(fnlog,"w")
end
написал: Переписал с помощью корутин, здесь их применение наиболее показательно.
Это можно сделать короче:
Код
RUN = true
function main ()
-- Функции для асинхронного запроса свечей ---
-- 1. Массовый запрос свечей BulkRequestCandles.
-- Параметр: таблица {{class_code, sec_code, interval}}
-- Результат: {{class_code, sec_code, interval, ds}}
local BulkRequestCandles = function (par)
for i = 1 , # par do
par[i].ds = CreateDataSource (par[i].class_code, par[i].sec_code, par[i].interval)
end
end
----------------------------------------
-- 2. Проверка запроса свечей CheckingCandleRequest.
-- Параметр: таблица {{class_code, sec_code, interval, ds}}
-- Результат в таблице парамктров : {{class_code, sec_code, interval, ds, ok}}
-- Значения ok: true - данные начали поступать; nil данные еще не поступили;
-- false - ошибка в параметрах запроса
-- Знвчение функции: количеситво источников еще ожидающих данные --
local CheckingCandleRequest = function (par)
local N = # par
local ds
for i = 1 , # par do
ds = par[i].ds
if type(ds) = = 'string' then -- обнаруженная ранее ошибка в параметрах запроса
N = N - 1
else
if par[i].ok = = nil then -- еще не дождались данных
if ds = = nil then -- обнаружена ошибка
par[i].ds = ' *** Ошибка в параметрах запроса'
par[i].ok = false
else
-- проверка поступления данных
if ds: Size () > 0 then -- есть данные
par[i].ok = true
N = N - 1
end
end
else
N = N - 1
end
end
end
return N
end
-------------------------------------------------
local sec_list = {}
sec_list[ # sec_list + 1 ] = {class_code = 'QJSIM' , sec_code = 'SBER' , interval = 1 }
sec_list[ # sec_list + 1 ] = {class_code = 'QJSIM' , sec_code = 'SBER' , interval = 2 }
sec_list[ # sec_list + 1 ] = {class_code = 'QJSIM' , sec_code = 'SBER' , interval = 5 }
sec_list[ # sec_list + 1 ] = {class_code = 'QJSIM' , sec_code = 'SBER' , interval = 10 }
sec_list[ # sec_list + 1 ] = {class_code = 'QJSIM' , sec_code = 'SBER' , interval = 20 }
sec_list[ # sec_list + 1 ] = {class_code = 'QJSIM' , sec_code = 'GAZP' , interval = 10 }
sec_list[ # sec_list + 1 ] = {class_code = 'QJSIM' , sec_code = 'GAZP' , interval = 2 }
sec_list[ # sec_list + 1 ] = {class_code = 'QJSIM' , sec_code = 'GAZP' , interval = 5 }
sec_list[ # sec_list + 1 ] = {class_code = 'QJSIM' , sec_code = 'LKOH' , interval = 5 }
sec_list[ # sec_list + 1 ] = {class_code = 'QJSIM' , sec_code = 'FEES' , interval = 5 }
sec_list[ # sec_list + 1 ] = {class_code = 'SPBFUT' , sec_code = 'SiZ5' , interval = 5 }
sec_list[ # sec_list + 1 ] = {class_code = 'SPBFUT' , sec_code = 'RIZ5' , interval = 5 }
sec_list[ # sec_list + 1 ] = {class_code = 'SPBFUT' , sec_code = 'RIZ5' , interval = 15 }
sec_list[ # sec_list + 1 ] = {class_code = 'SPBFUT' , sec_code = 'SRZ5' , interval = 30 }
BulkRequestCandles(sec_list)
--------------
local DS = false
while RUN do
-- Проверка поступления свечей (без блокирования цикла обработки)
if CheckingCandleRequest(sec_list) = = 0 and not DS then
DS = true
-- Отладочная печать --
for i = 1 , # sec_list do
if sec_list[i].ok = = true then
message (sec_list[i].sec_code .. ' ds:size() = ' .. sec_list[i].ds:Size()
..' interval = ' .. sec_list[i].interval)
else -- Ошибка задания параметров
message(sec_list[i].sec_code..' interval = ' .. sec_list[i].interval
.. sec_list[i].ds )
end
end
end
-- Выполнение заданий скрипта --
sleep ( 100 )
end
end
function OnStop (signal)
RUN = false
return 5000
end
сравните
Асинхронная подписка на свечи
Пользователь
Сообщений: Регистрация: 30.01.2015
21.11.2025 15:52:26
Это можно сделать так:
Код
--Пример ассинхронного запроса свечей--
--результат в массиве ds для каждого инструмента
Tclas={}
Tclas.QJSIM={SBER={int={1,2,5,10,20},ds={}}, GAZP={int={2,5},ds={}}, LKOH={int={5},ds={}}}
Tclas.SPBFUT={SiZ5={int={5},ds={}}, RIZ5={int={5,10},ds={}},SRZ5={int={30},ds={}}}
local tim=os.clock()
function OnParam(c,s)
local tc=Tclas[c]
if tc then local ts=tc[s];
if ts then local ts=tc[s]; local int=ts.int; local ds=ts.ds;local N=#int; local M=#ds;
if N~=M then local j=0;
while N>j do j=j+1;
if ds[j]==nil then local x=CreateDataSource(c,s, int[j]);
if x:Size()>0 then local ti=math.tointeger(1000*(os.clock()-tim)//1);
ds[j]=x; nkLog:write("time(ms)="..tostring(ti)..","..c..","..s..",j="..j..",int="..int[j]..",size="..ds[j]:Size().."\n"); nkLog:flush();
end
end
end
M=#ds; if N==M then nkLog:write(s..",подписка завершена\n"); nkLog:flush(); end
end
end
end
end
RUN = truefunction main()
while RUN do
-- Выполнение заданий скрипта --
sleep (10)
end
end
function OnStop(signal) RUN = false return 5000 end
function OnInit(p)
local p=string.reverse(p); local n,m=string.find(p,"\\");
local pS=string.reverse(string.sub(p,n)); name=string.reverse(string.sub(p,5,n-1)) ;
package.cpath =package.cpath..";"..pS.."?.dll;"
package.path =package.path..";"..pS.."?.lua;"..pS.."?.luac;"
fnlog=pS..name.."_nk.log"; nkLog=io.open(fnlog,"w")
end
В скрипте есть вывод в лог файл, который создается в каталоге скрипта. Результат работы скрипта на тестовом сервере QUIK
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 30.01.2015
21.11.2025 12:44:28
, Вы какой CHAT AI используете?
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 30.01.2015
18.11.2025 19:53:45
Вот еще информация к размышлению. В одном из вариантов робота реализовал подписку в колбеке Onparam. ------------------------ Размер кода функции подписки для любого числа инструментов 12 строк. (Двенадцать строк) -------------------------- Работает без задержек т е асинхронно. ----------------------- Вот лог файл работа такой подиписки. Время указано в ms ( для справки ms - 1/1000 секунды) Подписка на 10 интервалов занимает примерно 0.006 сек. В первой строке список инструментов на которы подписываемся и список интервалов Когда подписка закончилась то задержка работы колбека из-за вызова этой функции составляет 4 мкс это 0.000004 сек.
написал: А если поставить колбек то и тыкать не надо. Тратим время лишь когда приди данные. Что не так?
Не так, что этот колбек будет вызываться на всех барах истории, начиная с 1. Также он будет дергаться на каждую сделку. Это все лишние телодвижения. По крайней мере мне необходимо пройтись по последним, скажем 100 барам, а далее один раз на новый бар. Но да, можно и так, если организовать доп. проверки в этом колбеке.
Вы не правы. он дергается основным потоком ровно тогда когда тот запихивает данные в хранилище. Если нам не надо реагировать на незакрытую свечу, то в колбеке просто ее игнорируем. при приходе очередной закрытой свечи заданного тайма колбек вызовет функцию инструмента которому эти данные пришли. Таким образом никаких лишних телодвижений в потоке main нам делать не надо. И не надо тыкать куда-то чтобы проверить есть или нет данных. --------------------------- История тоже распознается без проблем ------------------------ Все доп проверки решаются парой операторов if Это примерно 300 наносекунд затрат времени.
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 30.01.2015
18.11.2025 17:36:15
Круто нагородили.
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
написал: Так и в нашем упрощённом варианте предусмотрен выход из цикла подписки.
Может я, конечно, невнимательно смотрел примеры, но все одни предполагали ожидание через цикл. Т.е. заказали - и тут же ждем. В итоге заказ 100 источников растягивается во времени, т.к. последний будет заказан только через 100*время ожидания. Что долго. Подход заказали все сразу в цикле и потом ждем все в цикле лучше, но тоже заблокирует скрипт пока ждем циклом. Здесь же заказ всех сразу. И периодически просто атомарно "тыкаем палочкой" на предмет данных. Пришли - можем делать что-то с данными. Нет - переходим к другим задачам, а эта пока путь остается. Т.е. ожидание не мешает другим задачам не связанным с данными, коих может быть много в скрипте.
А если поставить колбек то и тыкать не надо. Тратим время лишь когда приди данные. Что не так?
Обсуждаем интерфейс для робота
Пользователь
Сообщений: Регистрация: 30.01.2015
17.11.2025 18:16:45
Сейчас реализовал умную заявку. -------------------------------- В интерфейсе есть столбец с именем Qn - это желаемый размер позиции в лотах. ---------------------------- Работает это так. левой кнопкой увеличиваем Qn и робот будет докупать, правой кнопкой уменьшаем Qn и робот будет продавать. Покупает и продает он по лучшим ценам. В таблице есть параметр dp . этот параметр задает в минимальных шагах цены допустимый уход цены в заявке от лучшей цены. ------------------------ Алгоритм работы умной заявки можно заменить, подключив новую задачу вместо существующей. ----------------------- Управление заявками и задачами реализованы в конечном автомате и пользователь их не знает и не видит. В задачах выставление заявок можно задавать через события и колбеки, а стоп-заявку и ее параметры установить в таблице интерфейса .
Обсуждаем интерфейс для робота
Пользователь
Сообщений: Регистрация: 30.01.2015
17.11.2025 18:05:21
Сейчас пишу робота на основе ИИ Lua и QUIK. Кратко изложу интерфейс для работы с ним. --------------------- Интерфейс имеет такой вид:
содержание строк и столбцов задается двумя строками в файле инициализации робота:
Код
list_sec="ROSN,GAZP,SBER,PLZL,GMKN,CHMF,HYDR,LKOH,MOEX,SNGS" --список торгуемых инструментов
list_user_table="sec:-108,short:-4:0,int:4:1,quote:-4:0,stop:-108:1,spred:4:1,offset:4:1,dp:4:1,Qn:4:0,Q:4:0,last:8:0.,bid:8:0.,offer:8:0.,price:8:0.,prof:8:0."
-- описание столбцов
В таблице отображаются либо отдельные значения, либо значения из списка. Например, я задаю типы стоп заявок в виде :
Пользователь может изменять данные лишь двумя способами -- выбирать из существующего списка или изменять значение на плюс минус 1 нажатием правой или левой кнопки мышки.. Двойным щелчком мышки можно сделать значение активным или пассивным. ----------------- Например, можно сделать неактивными все инструменты ,кроме одного, и робот будет торговать лишь этим инструментом. Можно сделать неактивным стоп или short и робот не будет ставить стоп или покупать в шорт. ------------------------- Еще в файле инициализации задается список имеющихся алгоритмов торговли , я называю их задачами.
Код
list_task="task1,task2,task3,task4" -- список существующих задач
а также список задач для всех инструментов по умолчанию
Код
user_task={"task1","task2" } --задачи для каждого инструмента по умолчанию
для каждого инструмента можно указать индивидуальные параметры или задачи, которые в списке инструментов указываются через ":" ========================= Это весь интерфейс.
Конструктивные предложения приветствуются.
О торговле фьючерсами и ГО
Пользователь
Сообщений: Регистрация: 30.01.2015
17.11.2025 17:34:55
Если Вы обязались купить Потом обязались продать То у вас нет обязанности. вторая погасила первую ГО вам вернули. За вычетом разницы в цене и комис.
О торговле фьючерсами и ГО
Пользователь
Сообщений: Регистрация: 30.01.2015
17.11.2025 17:33:26
Фьючерс - это не товар, а обязанность ГО - это залог под исполнения этой обязанности.
О торговле фьючерсами и ГО
Пользователь
Сообщений: Регистрация: 30.01.2015
17.11.2025 17:31:37
Если Вы продаете то что уже купили то платите лишь комиссию Если Вы покупаете то что уже продали то аналогично
О торговле фьючерсами и ГО
Пользователь
Сообщений: Регистрация: 30.01.2015
17.11.2025 17:29:47
Цитата
Сергей Че написал: Допустим, я купил 2 фьючерса с ГО = 10 000 руб. Для их покупки у меня должно быть свободно минимум 2 * 10 000 руб = 20 000 руб, которые будут заморожены при покупке. Спустся время я хочу закрыть позицию. Для этого мне надо продать два фьючерса. И для этого у меня так же должны быть свободны 20 000 руб или нет? Получается, чтобы торговать фьючерсом с плечом Х, мне надо иметь 2 * Х * ГО руб свободных денег? Я прав? Или я где-то что-то недопонимаю?
Прикольно, Вы хотите платить и когда покупаете что-то и когда продаете что-то? --------------------------- Может лучше начать с чтения учебников, а не с реальной торговли?
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 30.01.2015
17.11.2025 17:12:16
, Поясняю. "Все смешалось, кони, люди" -------------------- Вы подписываетесь на параметр из ТТП а ждете свечи.Вы уж определитесь. ------------------------------------------------------------------------ "А, ты за большевиков, али за коммунистов?"
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
local WORKING_FLAG = true local class_code, sec_code = "TQBR", "SBER"--"SPBFUT", "RIZ5"
-- Простые переменные для данных local last_bid = "N/A" local last_offer = "N/A" local last_candle = nil local ds = nil
-- Прямые callback функции без сложных систем function OnParam(class_code, sec_code) if class_code == "SPBFUT" and sec_code == "RIZ5" then last_bid = getParamEx(class_code, sec_code, "bid").param_value or "N/A" last_offer = getParamEx(class_code, sec_code, "offer").param_value or "N/A" end end
function OnQuote(class_code, sec_code) -- Просто получаем стакан, но не обрабатываем чтобы не нагружать end
-- Callback для свечей local function onCandleUpdate(index) if ds and index = 30 then message(string.format("Статус: %d итераций, Bid=%s, Offer=%s", iteration, last_bid, last_offer))
local result = ds:SetEmptyCallback() -- SetUpdateCallback(onCandleUpdate) -- message("получать данные с сервера, размер: " .. ds:Size() ..' '..tostring(result) ) if ds:Size() and ds:Size()>0 then message(string.format("Свеча: O=%.1f H=%.1f L=%.1f C=%.1f", ds:O(ds:Size()), ds:H(ds:Size()), ds:L(ds:Size()), ds:C(ds:Size()) )) end
last_print_time = current_time end
-- ВАЖНО: Даем время QUIK обработать события sleep(1000) -- 1 СЕКУНДА - достаточно для избежания "Превышения времени" end
message("Робот остановлен") end
-- Простые обработчики остановки function OnStop() WORKING_FLAG = false if ds then ds:Close() end message("Робот остановлен по команде") end function OnClose() WORKING_FLAG = false if ds then ds:Close() end end function OnInit() message("Скрипт инициализирован") end
У Вас в скрипте ошибка Надо подписываться не так CreateDataSource(class_code, sec_code, 1,"last") а так CreateDataSource(class_code, sec_code, 1)
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 30.01.2015
17.11.2025 16:39:15
Повторю еще раз. Подписка делается однократно при запуске робота. Т е она не влияет на его работу никак.
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 30.01.2015
17.11.2025 16:37:35
далее создаю файл для сохранения данных текущего дня Для истории есть отдельная сжатая база глубиной 10 лет. Создаю колбек для обработки данных
Код
local fD=pTD..sec.."/"..int.."/current.txt"; --файл данных текущего дня
local fe=io.open(fD,"w");
if ds then ds:SetUpdateCallback(cb_candle(sec,ds,fe)); else ds={} end
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
пардон, не понял сначала . Расскажу как я делаю подписку. Число инструментов не имеет значения. Сейчас в разрабатываемом роботе 10 инструментов. ------------------------ Подписка делается один раз в функции получения параметров инструментов заданных списком в фале ini. вот фрагмент подписки.
Код
local ds,err;
if int>0 then --подписка на свечи
while ds==nil do ds,err=CreateDataSource(clas,sec,int); sleep(1); end
end
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 30.01.2015
17.11.2025 10:50:48
, Если скрипт не осилите, то покажите фрагмент кода, как Вы будете обрабатывать свечи отдельного инструмента/
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 30.01.2015
17.11.2025 10:44:48
, Если это у Вас универсальная система, то покажите код для произвольного числа инструментов, список которых будет задавать пользователь либо, этот список формирует сам робот исходя из состояния рынка.
Проблема с нажатием правой кнопки
Пользователь
Сообщений: Регистрация: 30.01.2015
17.11.2025 09:43:32
Когда в таблице в скрипте нажимаю правую кнопку мышки, то вылезает окно квика
Если не знаете, то спросите сначала у Алисы. -------------------------- Содержимое ответа
Понятие Scoping (области видимости) в языке программирования Lua определяет, насколько переменная видна остальной части программы. Это понятие относится к глобальным и локальным переменным. Область видимости — это участок кода программы, в пределах которого можно получить доступ к значению, хранящемуся в переменной. Под блоком понимается:
тело управляющей конструкции (if-then, else, for, while, repeat);
тело функции;
фрагмент кода, заключённый в ключевые слова do...end.
проблема с двойным нажатием кнопки
Пользователь
Сообщений: Регистрация: 30.01.2015
17.11.2025 09:21:59
Цитата
Станислав написал: Организовать какой-то адаптер, который будет заниматься подсчетом количества миллисекунд с нажатия и на основе этих данных отправлять сигнал либо об одиночном либо о двойном нажатии.
Спасибо. Решил проблему иначе. Запоминаю код предыдущего нажатия. Обработку одинарного нажатия выполняю по отпусканию клавиши.
проблема с двойным нажатием кнопки
Пользователь
Сообщений: Регистрация: 30.01.2015
16.11.2025 10:40:06
При двойном нажатии кнопки мыши в таблице созданной в скрипте всегда сначала приходит сигнал об одинарном нажатии кнопки.
Как устранить сигнал об одинарном нажатии при двойном нажатии?
Примеры простого торгового робота на Lua и Python от разработчиков QUIK, Примеры простого торгового робота на Lua и Python от разработчиков QUIK
Пользователь
Сообщений: Регистрация: 30.01.2015
14.11.2025 11:19:32
Цитата
Олег Денисов написал: Может есть у кого-нибудь такой "простой работающий робот qlua с выставлением стопа и профита"?
На сколько простой? ------------------------- В интернете можно найти много предложений роботов для QUIK за деньги . Вы удивитесь, но это все "простые" роботы.
Торговый счёт и код клиента
Пользователь
Сообщений: Регистрация: 30.01.2015
13.11.2025 20:42:01
спросите в браузере Яндекса Алису, она все объяснит простым русским языком.
У Вас скрипт работает лишь один раз. В майн надо делать бесконечный цикл. Читайте документацию.
Индекс запсииси в таблице ордеров
Пользователь
Сообщений: Регистрация: 30.01.2015
13.11.2025 12:18:42
Предположу, что так сбрасывают зависшие каналы, когда их много. ------------------- "Хотелось бы услышать начальника транспортного цеха"
Установка отметок на графике через скрипт
Пользователь
Сообщений: Регистрация: 30.01.2015
12.11.2025 20:06:40
Цитата
gngngn написал: Добрый день код который вы скинули кладет терминал
у меня скорей всего что то с самим терминалом, пробивал несколько простых скриптов, метки создаются - message (tostring(label_id_text)) выводи id метки
Чтобы выводились метки надо установить в скрипте интервал равный интервалу на графике. Установлено 5 минут. идентификатор графика установлен t ag = "SBER_ID" версия QUIK 12.8.0.6 сервер тестовый
Метки на графике в скрипте
Пользователь
Сообщений: Регистрация: 30.01.2015
12.11.2025 16:00:39
По просьбе трудящихся.
Код
label_params={["TEXT"]="",["IMAGE_PATH"]="",["ALIGNMENT"]="Left",["YVALUE"]=0,["DATE"]=0,["TIME"]=0,["R"]=255,["G"]=255,["B"]=255,
["TRANSPARENCY"]=0,["TRANSPARENT_BACKGROUND"]=0,["FONT_FACE_NAME"]='Times New Roman',["FONT_HEIGHT"]=10,["HINT"]=""}
function labeldraw(price, YYYYMMDD,HMS,textlabel, texthint)
label_params.TEXT = textlabel;
label_params.DATE = YYYYMMDD;
label_params.TIME =HMS;
label_params.YVALUE = price;
label_params.HINT = texthint;
label_id_text = AddLabel(tag, label_params)
end
function main()
local i=0; local _size=0;
while true do
local size= getNumCandles(tag);
while size>i do
local t, _, _ = getCandlesByIndex(tag, 0, i, 1)
local z=t[0]; local Hi,Li,Ci,Oi=z.high,z.low,z.close,z.open;
i=i+1;
local Ti=ds:T(i)
YYYYMMDD=100*(100*Ti.year+Ti.month)+Ti.day;
HMS=100*(100*Ti.hour+Ti.min)+Ti.sec;
labeldraw(Hi, YYYYMMDD,HMS,"A", "B")
end
sleep(1)
end
end
function OnInit(p) -- инициализация функции main
sec,clas,int="SBER","QJSIM",5;
tag = "SBER_ID"
ds=CreateDataSource ("sec","QJSIM",5)
while ds==nil do ds,err=CreateDataSource(clas,sec,int); sleep(1); end
end
Установка отметок на графике через скрипт
Пользователь
Сообщений: Регистрация: 30.01.2015
12.11.2025 15:56:51
, Вот решение Вашей хотелки - метки в скрипте:
это скрипт:
Код
label_params={["TEXT"]="",["IMAGE_PATH"]="",["ALIGNMENT"]="Left",["YVALUE"]=0,["DATE"]=0,["TIME"]=0,["R"]=255,["G"]=255,["B"]=255,
["TRANSPARENCY"]=0,["TRANSPARENT_BACKGROUND"]=0,["FONT_FACE_NAME"]='Times New Roman',["FONT_HEIGHT"]=10,["HINT"]=""}
function labeldraw(price, YYYYMMDD,HMS,textlabel, texthint)
label_params.TEXT = textlabel;
label_params.DATE = YYYYMMDD;
label_params.TIME =HMS;
label_params.YVALUE = price;
label_params.HINT = texthint;
label_id_text = AddLabel(tag, label_params)
end
function main()
local i=0; local _size=0;
while true do
local size= getNumCandles(tag) message (size)
-- if size>_size then price, _, _ = getCandlesByIndex(tiker_id, 0, size - 1, 1) _size=size; end
while size>i do
local t, _, _ = getCandlesByIndex(tag, 0, i, 1)
local z=t[0]; local Hi,Li,Ci,Oi=z.high,z.low,z.close,z.open;
i=i+1;
local Ti=ds:T(i)
YYYYMMDD=100*(100*Ti.year+Ti.month)+Ti.day;
HMS=100*(100*Ti.hour+Ti.min)+Ti.sec;
labeldraw(Hi, YYYYMMDD,HMS,"A", "B")
end
sleep(1)
end
end
function OnInit(p) -- инициализация функции main
sec,clas,int="SBER","QJSIM",5;
tag = "SBER_ID"
ds=CreateDataSource ("sec","QJSIM",5)
while ds==nil do ds,err=CreateDataSource(clas,sec,int); sleep(1); end
end
Установка отметок на графике через скрипт
Пользователь
Сообщений: Регистрация: 30.01.2015
12.11.2025 14:16:33
Общие сведения
Индикаторы технического анализа представляют собой отдельный класс скриптов, которые удовлетворяют определенным условиям и расположены в папке LuaIndicators в каталоге терминала. Если папка отсутствует в каталоге, необходимо создать ее вручную. Список скриптов не доступен из диалога Сервисы / LUA скрипты....
При добавлении нового индикатора на график плагин qlua сканирует папку LuaIndicators, проверяет файлы с расширением lua и luac (скомпилированные скрипты lua) на соответствие следующим требованиям:
определена функция Init,
определена функция OnCalculate,
определена таблица Lua с именем Settings, в которой есть поле «Name».
Пример минимального корректного кода для индикатора:
Settings={} Settings.Name = "minimal" function Init() return 1 end function OnCalculate(index) return 1 end
Установка отметок на графике через скрипт
Пользователь
Сообщений: Регистрация: 30.01.2015
12.11.2025 14:14:35
Цитата
gngngn написал: день день. Помоги решить вопрос на графике не отображается метка (текст) причем при проверки message (tostring(label_id_text)) сообщение выдает id метки Так же на графике при нажатии правой кнопки при выборе удалить, строка "все метки в диаграмме" становится активной (получается метка на график попадает, но ее не видно) скрипт отображения метки следующий:
function labeldraw(price, textlabel, texthint) label_params = { TEXT = textlabel, ALIGNMENT = "LEFT", DATE = tostring(os.date("%Y%m%d")), TIME = tostring(os.date("%H%M%S")), R = 0, G = 0, B = 0, TRANSPARENCY = 90, FONT_HEIGHT = 10, TRANSPARENT_BACKGROUND = 1, YVALUE = price, HINT = texthint }
text = "ppppp "..price[0].close labeldraw(price[0].close, text, "eeeeee") message (tostring(price[0].close)) message (tostring(label_id_text)) end
Метки выставляются в индикаторе, а вы написали скрипт.
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 30.01.2015
06.11.2025 18:49:50
поправил комментарии
Код
list={
--список инструментов для портфеля
sec="ROSN,GAZP,SBER,PLZL,GMKN,CHMF,HYDR,LKOH,MOEX,SNGS"
task="task1,task2,task3,task4" -- список существующих задач
}
user_sec=" interval:1,quote:0,short:0,stop:0,takeprofit:0,task:task1:task2,quota:0"
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 30.01.2015
06.11.2025 18:48:51
сделал новый интерфейс еще проще:
Код
list={
--список инструментов для портфеля, если нет, то все инструменты по заданным классам
sec="ROSN,GAZP,SBER,PLZL,GMKN,CHMF,HYDR,LKOH,MOEX,SNGS"
task="task1,task2,task3,task4" -- список существующих задач
}
user_sec=" interval:1,quote:0,short:0,stop:0,takeprofit:0,task:task1:task2,quota:0"
--user_sec--параметры пользователя для sec по умолчанию--interval --интервал свечей --quote --подписка на стакан --short -- разрешениe коротких позиций --stop--флаг разрешения установки стопа 1 -обычный, 2-скользящий, --takeprofit, -- флаг разрешения TakePrifit --task---список задач по умолчанию для каждого инструмента --quota--для средств для покупки в одной заявке --можно задавать индивидуальные параметры для задач и инструментов
Система принятия решений и/или Нечеткая логика(FuzzyLogic), Нечеткая логика или Система принятия решений в трейдинге
Пользователь
Сообщений: Регистрация: 30.01.2015
06.11.2025 18:36:10
, Возможно Вы не обратили внимание, но у меня ВСЯ УНИВЕРСАЛЬНАЯ СИСТЕМА это 380 операторов из них 120 - это конечный автомат обработки колбеков и 60 - конечный автомат обработки задач. ----------------------------- + скрипты задач. которые могут создать событие на выставление удаление перестановку заявок. ---------------------- Интерфейс к ней показал ранее.