Алексей Овечкин
Алексей Овечкин личный блог
10 мая 2021, 02:18

Безубыточный робот

Безубыточный робот

Нашел интересный алгоритм.

https://www.youtube.com/watch?v=inJ8zuSoJTM
Показалась Грааль.

Написал робота под квик. Счастье не наступило.

Гонял на сбере, сишки, Евро-рубль.

Низкая доходность (меньше 1% в день) и все время разворачивается на откатах, из-за чего пытается задействовать большую часть депозита. В основном 2-4 разворота за цикл, но однажды 15 раз крутанулся, торговлю я ему конечно на 6 развороте отключил (в робота зашито).

Поменял алгоритм, сделал, чтоб торговал по тренду без начальной проверке, на втором цикле, и далее. Стало по лучше, но не существенно, необходимых 2% не добрал.

Если бы не попытки задействовать весь депозит, сгодился бы для разнообразия. А так блокирует пол депозита, а доходность маленькая.

Народ, если есть у кого интересные алгоритмы пиши, обкатаем.

Код робота: LUA, под 8 квик

Здесь только основной алгоритм, в нем задействованы библиотеке работы с окном, отчетность, общение с биржей, …

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

--[[
Робот-2021-2 — Зигзаг

]]
--+------------------------------------------------------------------+
--| Глобальные переменные |
--+------------------------------------------------------------------+

— Инструмент фьчей
ACCOUNT = '00000'; — Идентификатор счета (для фьчей, счет депо)
CLIENT_CODE = '00000'; — Код клинта, для фьчей ACCOUNT и CLIENT_CODE совпадают
CLASS_CODE = 'SPBFUT'; — Код класса (биржа) — TQBR — Акции, SPBFUT — Фьючерсы
SEC_CODE = 'EuM1'; — Код бумаги
SEC_NAME = 'Евро-рубль'; — Имя бумаги
PRICE_STEP = 1; — Шаг цены
PRICE_X = 1; — Шаг цены

QUIK_CODE = 0; — Инициализационный код терминала QUIK — НЕИСПОЛЬЗУЕТСЯ

— Имя файла отчета
vReportsName = «C:\\R\\Reports-011-»; — к имени файла добавляется дата и время. Исли файл уже существует, то запись идет в него.
— Файл отчета создается с расширением ".txt2". Читаем блокнотом или Notepad++.
--+------------------------------------------------------------------+
--| Настройки цикла |
--+------------------------------------------------------------------+

vLOTS = 1; — Количество лотов в шаге
vPROFIT = 96*PRICE_STEP; — Количество пунктов профита, после которого выходим

vPRICE_SEGMENT = 3; — Отрезок цены для анализа направления движения
--+------------------------------------------------------------------+
--| Рабочии переменные |
--+------------------------------------------------------------------+
vID = 1; — Номер следующей заявки
vIntervalID1 = 1;
vIntervalID1 = 10000;

vTrend = 0; — Тренд, направление движения: 1 — вверх, -1 — вниз

— Переменные для определения тренда
vPrice = {}; — Текущая цена, раз в секунду, из стакана, таблица из 25 ячеек, от 0 до 24
vPriceIndex = -1; — Индекс текущей ячейки vPrice

— Таблица цикла
vSTATUS = nil; — nil — Нет открытых сделок, и vTrend == 0, Таблица не активна
— 0 — Ожидание Входа в сделку —
— 1 — Вход совершен
— 7 — Выход

is_run = true; — Флаг безконечного цикла в main
vTrendFlag = 0; — Показывает направление предыдущего цикла, что бы что бы следующий цикл начинался со сделки.
--+------------------------------------------------------------------+
--| Внешние модули |
--+------------------------------------------------------------------+
package.path = «C:\\R\\Robot-2020-07\\?.lua»; — Каталог где лежат дополнительные модули. Скрипт лежит там же.
require «Reports-2020»; — Модуль печати отчета
require «Data-2020»; — Модуль Запроса данных
require «Trade-2020»; — Модуль торговых заявок
require «CrabWin-2020»; — Модуль окна
--+------------------------------------------------------------------+
--| Функция инициализации. |
--| ВЫЗЫВАЕТСЯ ТЕРМИНАЛОМ QUIK в самом начале, один раз. |
--+------------------------------------------------------------------+
function OnInit()
— —
— Открываем файл отчета
FunOpenFile();
— —
— Создаем и инициализируем окно
vTableName = «Зигзаг-02 — »… SEC_NAME;
QTable.__index = QTable;
vWinLink = QTable:new();
InitTable();
— --------------------------------------------------------------------------
end;
--+------------------------------------------------------------------+
--| Функция проверки потери связи с сервером QUIK |
--+------------------------------------------------------------------+
function OnDisconnected()
local DateTime = os.date("*t"); — таблица
FunSetMessege(«Потеря связи с сервером QUIK!», vErorrColour);
— Отчет ------------------------------------------------------------
vFileReportsStr = "->"… DateTime.day… "."… DateTime.month… "."… DateTime.year… " "… DateTime.hour… ":"… DateTime.min… ":"… DateTime.sec… " — "… os.clock()… " ";
vFileReportsStr = vFileReportsStr… «Потеря связи с сервером QUIK!»… "\n";
FunWriteFile();
message('Потеря связи с сервером QUIK!');
is_run = false
end
--+------------------------------------------------------------------+
--| Функция проверки ошибки заявки |
--+------------------------------------------------------------------+
function OnTransReply (vtrans_reply)

end
--+------------------------------------------------------------------+
--| Функция проверки таблицы сделок |
--+------------------------------------------------------------------+
function OnOrder(vOrder)

— Набор позиции
if vSTATUS ~= nil then — Таблица активна
--if vOrder.trans_id == vCycleTab.TRANS_ID and vOrder.sec_code == SEC_CODE and vOrder.uid == QUIK_CODE then — Проверка, наша ли это транзакции.
--vCycleTab.BALANCE = vOrder.balance; — Остаток
--vCycleTab.ORDER = vOrder.order_num; — Номер заявки в торговои? системе
--end
end
end
--+------------------------------------------------------------------+
--| Функция параллельной обработки. |
--+------------------------------------------------------------------+
function main()
— --------------------------------------------------------------------------
local i = 0;
local mm = 0;
local xx = 0;
local yy = 0;
local zz = 0;

local vSTATUS = nil;
local vTREND = 0;
local vOPENPRICE = 0;
local vOPENPRICE1 = 0;
local vOPENPRICE2 = 0;
local vQUANTITY = 0;
local vvProfit = 0;

local vDateTime = os.time(); — Текущая дата в секундах

— --------------------------------------------------------------------------
— Начало работы
— —
while is_run do

vDateTime = os.date("*t"); — таблица времени
if vDateTime.hour >= 7 and vDateTime.hour <= 23 then
— Запрос последней цены —
for i = 0, 10 do
xx = getParamEx(CLASS_CODE, SEC_CODE, 'LAST');
if xx.result == «1» and param_image ~= "" and param_type ~= «0» then break; end
end
if xx.result == «0» or xx.result == «0.0» or xx.param_value == 0 or xx.param_value == «0» then — Обаротка ошибки запроса
FunSetMessege(«Ошибка запроса цены покупки », vErorrColour, «Цена »… xx.param_value);
is_run = false;
else
— Цена получена
vPriceIndex = vPriceIndex + 1;
vPrice[vPriceIndex] = tonumber(xx.param_value); — Текущая цена, раз в секунду,
xx = nil;
end

— Экономия памяти
if vPriceIndex > 200 then
for i = 0, 100 do vPrice[i] = vPrice[100+i]; end
vPriceIndex = 100;
end

end — Время

--if vSTATUS ~= nil then FunSetMessege(" >> "… vSTATUS… " vPrice >> " ..vPrice[vPriceIndex]… " vTrendFlag >> "… vTrendFlag… " vOPENPRICE1 >> "… vOPENPRICE1… " vOPENPRICE2 >> "… vOPENPRICE2); end
— Начало —
if vPriceIndex >= 2 and vSTATUS == nil then — Начало цикла

vSTATUS = 0; — 0 — Вход в сделку
vTREND = 0;
vOPENPRICE = vPrice[vPriceIndex];
vOPENPRICE1 = vPrice[vPriceIndex] + vPROFIT/2; — Цена точки входа
vOPENPRICE2 = vPrice[vPriceIndex] — vPROFIT/2; — Цена точки входа
vQUANTITY = vLOTS; — Рабочий объем цикла (в лотах):

— Второй и следующии циклы идут как продолжение предыдущего цикла
if vTrendFlag == 1 then
vTREND = 1;
vOPENPRICE1 = vPrice[vPriceIndex]; — Цена точки входа
vOPENPRICE2 = vPrice[vPriceIndex] — vPROFIT; — Цена точки входа
end
if vTrendFlag == -1 then
vTREND = -1;
vOPENPRICE1 = vPrice[vPriceIndex] + vPROFIT; — Цена точки входа
vOPENPRICE2 = vPrice[vPriceIndex]; — Цена точки входа
end

FunSetMessege(«Начало: Цена: »… vOPENPRICE1… " <> "… vOPENPRICE2… " Лотов: "… vQUANTITY);
end
— Вход в сделку —
if vSTATUS ~= nil and vSTATUS == 0 and is_run == true then —
xx = 0;
if vPriceIndex > vPRICE_SEGMENT then xx = vPrice[vPriceIndex] — vPrice[vPriceIndex-vPRICE_SEGMENT]; end
if vPrice[vPriceIndex] >= vOPENPRICE1 and xx >= 0 then
vResult = FunTrans(vQUANTITY, «M», vPrice[vPriceIndex]); — Покупаем, отложенный ордер
vOPENPRICE1 = vPrice[vPriceIndex];
vOPENPRICE2 = vOPENPRICE1 — vPROFIT;
if vResult == -1 then is_run = false; end — Ошибка в функции FunTrans, конец работы
vSTATUS = 2;
end
if vPrice[vPriceIndex] <= vOPENPRICE2 and xx <= 0 then
vResult = FunTrans(-vQUANTITY, «M», vPrice[vPriceIndex]); — Покупаем, отложенный ордер
vOPENPRICE2 = vPrice[vPriceIndex];
vOPENPRICE1 = vOPENPRICE2 + vPROFIT;
if vResult == -1 then is_run = false; end — Ошибка в функции FunTrans, конец работы
vSTATUS = 2;
end
end
— Проверка входа в сделку -------------------------------------------------------------------------------------
if vSTATUS ~= nil and vSTATUS == 2 and is_run == true then —
FunChecklots();
if BuyVol ~= 0 then
vTREND = 1;
vProfit = vOPENPRICE1 + vPROFIT;
FunCloseAllOrder();
vResult = FunTrans(-vQUANTITY, «L», vProfit); — Продаем, отложенный ордер
if vResult == -1 then is_run = false; end — Ошибка в функции FunTrans, конец работы
FunSetMessege(«Вход: тренд Растущий: Цена: »… vOPENPRICE1… " Лотов: "… vQUANTITY, vUpColour);
vSTATUS = 1;
end
if SellVol ~= 0 then
vTREND = -1;
vProfit = vOPENPRICE2 — vPROFIT;
FunCloseAllOrder();
vResult = FunTrans(vQUANTITY, «L», vProfit); — Покупаем, отложенный ордер
if vResult == -1 then is_run = false; end — Ошибка в функции FunTrans, конец работы
FunSetMessege(«Вход: тренд Падающий: Цена: »… vOPENPRICE2… " Лотов: "… vQUANTITY, vDownColour);
vSTATUS = 1;
end
end
— Разворот ---------------------------------------------------------------------------------------------------

if vSTATUS ~= nil and vSTATUS == 1 and is_run == true then —
xx = 0;
if vPriceIndex > vPRICE_SEGMENT then xx = vPrice[vPriceIndex] — vPrice[vPriceIndex-vPRICE_SEGMENT]; end
if vTREND == 1 and vPrice[vPriceIndex] <= vOPENPRICE2 and xx <= 0 then
xx = 3*vQUANTITY;
vResult = FunTrans(-xx, «M», vOPENPRICE2); — Продаем, отложенный ордер
if vResult == -1 then is_run = false; end — Ошибка в функции FunTrans, конец работы
vSTATUS = 3;
end
if vTREND == -1 and vPrice[vPriceIndex] >= vOPENPRICE1 and xx >= 0 then
xx = 3*vQUANTITY;
vResult = FunTrans(xx, «M», vOPENPRICE1); — Покупаем, отложенный ордер
if vResult == -1 then is_run = false; end — Ошибка в функции FunTrans, конец работы
vSTATUS = 3;
end
end

— Проверка разворота —
if vSTATUS ~= nil and vSTATUS == 3 and is_run == true then —
FunChecklots();
if vTREND == 1 then
if SellVol ~= 0 then — Разворот
FunCloseAllOrderID();
vQUANTITY = vQUANTITY + vQUANTITY;
vTREND = -1;
FunSetMessege(«Разворот »… vOPENPRICE2);
vSTATUS = 2;
end
end
if vTREND == -1 then
if BuyVol ~= 0 then — Разворот
FunCloseAllOrderID();
vQUANTITY = vQUANTITY + vQUANTITY;
vTREND = 1;
FunSetMessege(«Разворот »… vOPENPRICE1);
vSTATUS = 2;
end
end
end

— Проверка выхода из сделки ------------------------------------------------------------------------------------------
if vSTATUS ~= nil and vSTATUS == 1 and is_run == true then —
FunChecklots();
if BuyVol == 0 and SellVol == 0 then — Профит
vSTATUS = 7;
end
end
— Выход из сделки ------------------------------------------------------------------------------------------
if vSTATUS ~= nil and vSTATUS == 7 and is_run == true then
FunChecklots();
if BuyVol == 0 and SellVol == 0 then
if vTREND == 1 then
xx = vProfit — vOPENPRICE1;
xx = xx * vQUANTITY;
FunSetMessege(«Профит = »… vProfit… " — "… vOPENPRICE1… " = "… xx);
vTrendFlag = 1;
end
if vTREND == -1 then
xx = vOPENPRICE2 — vProfit;
xx = xx * vQUANTITY;
FunSetMessege(«Профит = »… vOPENPRICE2… " — "… vProfit… " = "… xx);
vTrendFlag = -1;
end

vSTATUS = nil;
— снять все активные заявки
FunCloseAllOrderID();
end
end

sleep (1000); — приостановка (1000 = на 1 секунда)

--end;
end;
— --------------------------------------------------------------------------
FunCloseFile(); — Закрываем файл отчета
— --------------------------------------------------------------------------
end

--+------------------------------------------------------------------+
--| Функция при нажатии кнопки «Остановить». |
--+------------------------------------------------------------------+
function OnStop()

is_run = false

end
--+------------------------------------------------------------------+
--| |
--+------------------------------------------------------------------+

14 Комментариев
  • wistopus
    10 мая 2021, 07:41
    Низкая доходность (меньше 1% в день)
    меня устраивает вполне и 0,5% от всего депо в день.....
    и даже 0,25% тоже устраивает....
    • bocha
      10 мая 2021, 07:57
      wistopus,  вы, батенька, истинный дауншифтер!
      • wistopus
        10 мая 2021, 12:35
        Алексей Овечкин, 
        0,5% можно за полчаса, в 10 утра сделать
        можно...
        основной рывок, как правило, утром… днем провал… к вечеру половина от утреннего гэпа… (некоторые утром  деньги тока и делают… а потом весь день свободны....)…
  • wistopus
    10 мая 2021, 08:27
    истинный даун......шифтер....!

    bocha,

    Тимофей Тимофеевич строго настрого... запретил на его сайте ругаться Матом....
    • bocha
      10 мая 2021, 08:44
      wistopus,   дык я матом и не ругаюсь.  Разговариваю!
      Для поругаться мне и обыденного лексикона в избытке хватает ))
  • Vladimir N.
    10 мая 2021, 14:23
    А руками слабо?) Не там храаль лежит.
      • Vladimir N.
        10 мая 2021, 16:37
        Алексей Овечкин, Понятно, ну да, это верно. А как же средне/долгосрок? 

          • Vladimir N.
            11 мая 2021, 13:21
            Алексей Овечкин, у меня настало даже на минутках и вообще любом ТФ. Я не программист, хоть все пытаюсь изучать сам это дело, все вручную торгую.
              • Vladimir N.
                13 мая 2021, 08:40
                Алексей Овечкин, да, гибче, но медленее. Поэтому и пытаюсь. 
  • Андрей Беляев
    30 сентября 2021, 12:21
    Добрый день.
    А рабочий вариант не выкладывали? полный

Активные форумы
Что сейчас обсуждают

Старый дизайн
Старый
дизайн