СыроеШкин
СыроеШкин личный блог
19 мая 2016, 17:09

Для Quik. Авто тейк & стоп. Новый подход, код.

Терминал позволяет разрабатывать самодельные индикаторы, работающие в отдельном потоке. Но индикаторам можно давать и дополнительную нагрузку, реализовывать даже легких роботов-индикаторов, торгующих автономно. Из плюсов – получаем штатное диалоговое окно средствами Квика, что-то рисуем не отходя от кассы…   Не требуется подключения внешних библиотек для работы и отображения диалоговых окон, что повышает надежность и простоту установки.
Для примера сделал вполне рабочую программку авто стоп-тейк. Торговлю для примера на скользящих делать не стал, никому не нужна, а автостоп пригодится. Проверял на собственном реальном счете – работает. Пользуйтесь на здоровье!
   Есть один недостаток: по одному графику инструмента (бумаги) не может работать индикатор, получающий данные извне этого графика (как этот) и луа скрипт с main. Происходит конфликт и  Квик подвисает. Поэтому сейчас становится сложно надежно графически отобразить арбитражный спред например и его торговать. Но эту проблемку разработчики терминала обещают устранить в свежей версии.

    Работает только на срочном рынке!!! Можно совместно допилить до универсальности ко всем рынкам… Буду рад любым дополнениям, выложенным в открытый доступ.
Тут вынужден предупредить: на рынок уходят реальные заявки, поэтому любые необдуманные эксперименты с кодом могут привести к плачевным последствиям!!!

Инструкция после кода.

Settings={}
Settings.Name = "тейк и стоп FUT_L"
Settings.client_code="0"
Settings.loss=0
Settings.loss_prosk=0
Settings.profit=0
Settings.profit_otstup=0
Settings.profit_prosk=0

Sorder=true
idx_prosl=-1
Zapusk=true

function get_balance(sec, client_code)
local limit={}
local n=getNumberOf("futures_client_holding")
for i=0,n-1 do
limit = getItem("futures_client_holding", i)
if limit~=nil and limit.seccode== sec and limit.trdaccid==client_code then
return tonumber(limit.totalnet)
end
end
return 0
end

function get_latestprice(sec, client_code)
local ord={}
local n=getNumberOf("trades")
for i=n-1,0,-1 do
ord = getItem("trades", i)
if ord~=nil and ord.sec_code==sec and (ord.client_code==client_code or ord.account==client_code) then
return tonumber(ord.price)
end
end
return 0
end

function Init()
return 1
end

function TP_SL(class,security,direction,volume,stopprice,price,dealprice,offset,defspread,exp_date,comment)
        if (class==nil or security==nil or direction==nil or volume==nil or dealprice==nil  or offset==nil or defspread==nil) then
                return nil, "AUTOMATIK_STOP_FUT: нет одного из параметров стоп-заявки."
                end
        local trans_id = string.format('%d', math.random(2000000000))
        local err = sendTransaction({
    TRANS_ID=trans_id,
    ACTION='NEW_STOP_ORDER',
    STOP_ORDER_KIND='TAKE_PROFIT_AND_STOP_LIMIT_ORDER',
    CLASSCODE=class,
    SECCODE=security,
    ACCOUNT=Settings.client_code,
    CLIENT_CODE=Settings.client_code,
    OPERATION=direction,
    QUANTITY=tostring(volume),
    PRICE=tostring(price),
    EXPIRY_DATE='GTC',
    MARKET_STOP_LIMIT='NO',
    MARKET_TAKE_PROFIT='NO',
    IS_ACTIVE_IN_TIME='NO',
    OFFSET=tostring(offset),
    OFFSET_UNITS='PRICE_UNITS',
    STOPPRICE=tostring(dealprice), <br>    STOPPRICE2=tostring(stopprice), 
    SPREAD=tostring(defspread),
    SPREAD_UNITS='PRICE_UNITS',
    COMMENT='TP_SL'
  })

        if err~="" then
                return nil, "AUTOMATIK_STOP_FUT результат: "..err
        else
                return trans_id, ""
        end
end

function OnCalculate(idx)
if Zapusk then
class=getDataSourceInfo().class_code
sec=getDataSourceInfo().sec_code
old_balance=get_balance(sec, Settings.client_code)
Zapusk=false
end
if idx_prosl==idx then
balance=get_balance(sec, Settings.client_code)
if balance>0 and old_balance<balance then
Sorder=false
if old_balance<0 then
spr_balance=balance
else
spr_balance=balance-old_balance
end
end
if balance<0 and old_balance>balance then
Sorder=false
if old_balance>0 then
spr_balance=0-balance
else
spr_balance=old_balance-balance
end
end
if balance~=0 and not Sorder then
Open_Price=get_latestprice(sec, Settings.client_code)
if balance>0 and Open_Price~=0 then
dealprice=Open_Price+Settings.profit  --тейк
stopprice=Open_Price-Settings.loss  --стоп цена
price=stopprice-Settings.loss_prosk   --стоп с запасом
offset=Settings.profit_otstup --отход от тейка
defspread=Settings.profit_prosk  --проск тейка
Tr_Id,STR=TP_SL(class,sec,"S",spr_balance,stopprice,price,dealprice,offset,defspread,nil,nil)
Sorder=true
if Tr_Id==nil then
message(" "..STR,1)
end
end
if balance<0 and Open_Price~=0 then
dealprice=Open_Price-Settings.profit  --тейк
stopprice=Open_Price+Settings.loss  --стоп цена
price=stopprice+Settings.loss_prosk   --стоп с запасом
offset=Settings.profit_otstup --отход от тейка
defspread=Settings.profit_prosk  --проск тейка
Tr_Id,STR=TP_SL(class,sec,"B",spr_balance,stopprice,price,dealprice,offset,defspread,nil,nil)
Sorder=true
if Tr_Id==nil then
message(" "..STR,1)
end
end
end
old_balance=get_balance(sec, Settings.client_code)
end
idx_prosl=idx
return nil
end

Принцип работы: при активации автостоп_фут получает параметры инструмента на графике которого он открыт (код и класс), проверяет баланс по инструменту (если уже есть открытая позиция, не выставляет на нее тейк-стоп заявку). При увеличении позиции  выставляет на сервер брокера стандартную тейк-стоп заявку по введенным в настройках параметрам на то количество, на сколько увеличена позиция. Лонг или шорт определяет сам. Цену открытия позиции определяет как цену последней сделки, если сделки прошли по разной цене.

При закрытии позиции частично или полностью вручную (не по выставленным тейк-стоп заявкам) эти заявки остаются, нужно скорректировать их тоже тогда вручную!!!

На графике ничего не рисует, но можно при настройке на вкладке «Дополнительно» выбрать «Показывать стоп-заявки» и др.

Как пользоваться: 
— В папке с Квиком создать, если нет, папку обязательно с именем LuaIndicators
— открыть блокнот (например), скопировать в него код и сохранить в LuaIndicators с любым именем (Auto_TeikStop.lua например) но обязательно с расширением .lua

Открыть, если не открыта, в терминале таблицу « Позиции по клиентским счетам (фьючерсы)», в этой таблице должны быть колонки: «Торговый счет», «Код инструмента», «Тек. чистая», без этого работать не будет.

Открыть, если не открыта, таблицу стоп-заявок для визуального контроля.

Дальше добавляем на график инструмента, по которому будем использовать индикатор_автостоп_фут, как обычный индикатор в любое окно: в списке доступных индикаторов имя «тейк и стоп FUT_L». В открывшемся окне индикатора вместо нулей вводим:

 client_code – код клиента из таблицы «Позиции по клиентским счетам (фьючерсы)» из колонки «Торговый счет».

Вводим кратно шагу цены:

loss – сколько от цены открытия позиции до срабатывания стопа;

loss_prosk – разница между ценой срабатывания стопа и заявкой, которая пойдет на биржу;

profit – сколько от цены открытия позиции до начала активации расчета тейка;

profit_otstup – на сколько можно ухудшиться от профитного экстремума для фиксации прибыли (если ноль – то закроет сразу по достижении тейка);

profit_prosk – разница между ценой срабатывания тейка и заявкой, которая пойдет на биржу.

Нажимаем «сохранить» и автостоп активен.

Можно добавить эти параметры сразу в код, при неактивном индикаторе, и они будут установлены по умолчанию.

 Например.

   Надо защитить любую открываемую позицию по RIM6 на счете SPBFUT******* (client_code):

 по тейк-профиту: если прибыль 1500 (profit) пунктов от цены открытия — начать расчет тейка, когда цена отойдет на 200 (profit_otstup) пунктов от профитного экстремума с начала расчета тейка, отправится заявка по цене  с запасом на проскальзывание 500 пунктов (profit_prosk);

и по стоп-лимиту: если убыток 1000 (loss) пунктов от цены открытия, отправится заявка по цене  с запасом на проскальзывание 300 пунктов (loss_prosk)

Для этого добавляем на график RIM6  индикатор_автостоп_фут, как обычный индикатор в любое окно: в списке доступных индикаторов имя «тейк и стоп FUT_L». В открывшемся окне индикатора вместо нулей вводим:

 client_code      SPBFUT*******

loss                   1000

loss_prosk        300

profit                1500

profit_otstup    200

profit_prosk     500

нажать «сохранить» и автостоп_фут активен. Теперь любая позиция открытая после активации по RIM6  на счете SPBFUT******* будет защищена стандартной тейк-стоп заявкой. Лонг открыт или шорт и цену открытия, и размер позиции индикатор определяет сам.

  Если тейк-стоп заявка была отклонена, появится сообщение с причиной отклонения. Надо будет выставить стоп вручную, проверить параметры и лимиты.

Важно: При изменении параметров и активации будут действовать новые параметры. Ранее выставленные тейк-стоп заявки сохранятся. 

Профитной торговли!
25 Комментариев
  • Бывалый
    19 мая 2016, 20:12
    спасибо
  • Евгений Гуревич
    19 мая 2016, 20:20
     При увеличении позиции  выставляет на сервер брокера 
    Что значит «при увеличении позиции»?
      • Иван
        26 мая 2016, 15:18
        СыроеШкин, у меня ошибку выдает при запуске lua-скрипта:
    • Иван
      26 мая 2016, 16:03
      СыроеШкин, я у себя исправил, убрал <br>, ничего не происходит. Ошибку не выдает, но и запуск не идет. Пробовал на двух квиках от разных счетов.
    • Иван
      26 мая 2016, 16:17
      СыроеШкин, да, появилось. Спасибо!
        • Chillout
          07 ноября 2016, 13:03
          СыроеШкин, при заключении сделки вылетает окно где написано Превышен допустимый срок действия стоп-заявки (максимальное количество дней 30, по 2016.12.6 включительно)., где исправить? Спасибо
            • Chillout
              11 ноября 2016, 17:09
              СыроеШкин, Благодарю!
  • Александр
    02 февраля 2017, 17:13
    ++
  • Popiros
    24 августа 2018, 00:24
    Спасибо за Вашу помощь!
  • Ro Amy
    26 февраля 2019, 17:47
    Спасибо! А можно где сменить тип стоп заявки на рыночную? Часто приходится двигать стоп, если делать это на графике, при лимитной заявке, получается отложка(
  • Popiros
    21 декабря 2020, 14:27
    Добрый день! Как оставить в коде только один тейк-профит, а стоп-лосс убрать.
  • shtur2005
    24 февраля 2022, 01:14
    Добрый день!
    Индикатор хороший, но опробовать не удалось.
    Его нет в списке доступных индикаторов. Папка с индикаторами создана давно. Все остальные индикаторы отображаются
  • Indikk
    23 октября 2023, 19:24

    Settings={}
    Settings.Name = «SL_TP»
    Settings.client_code=""
    Settings.loss=0.020
    Settings.loss_prosk=0
    Settings.profit=0.040
    Settings.profit_otstup=0
    Settings.profit_prosk=0

    Sorder=true
    idx_prosl=-1
    Zapusk=true

    function get_balance(sec, client_code)
    local limit={}
    local n=getNumberOf(«futures_client_holding»)
    for i=0,n-1 do
    limit = getItem(«futures_client_holding», i)
    if limit~=nil and limit.seccode== sec and limit.trdaccid==client_code then
    return tonumber(limit.totalnet)
    end
    end
    return 0
    end

    function get_latestprice(sec, client_code)
    local ord={}
    local n=getNumberOf(«trades»)
    for i=n-1,0,-1 do
    ord = getItem(«trades», i)
    if ord~=nil and ord.sec_code==sec and (ord.client_code==client_code or ord.account==client_code) then
    return tonumber(ord.price)
    end
    end
    return 0
    end

    function Init()
    return 1
    end

    function TP_SL(class,security,direction,volume,stopprice,price,dealprice,offset,defspread,exp_date,comment)
    if (class==nil or security==nil or direction==nil or volume==nil or dealprice==nil or offset==nil or defspread==nil) then
    return nil, «AUTOMATIK_STOP_FUT: нет одного из параметров стоп-заявки.»
    end
    local trans_id = string.format('%d', math.random(2000000000))
    local err = sendTransaction({
    TRANS_ID=trans_id,
    ACTION='NEW_STOP_ORDER',
    STOP_ORDER_KIND='TAKE_PROFIT_AND_STOP_LIMIT_ORDER',
    CLASSCODE=class,
    SECCODE=security,
    ACCOUNT=Settings.client_code,
    CLIENT_CODE=Settings.client_code,
    OPERATION=direction,
    QUANTITY=tostring(volume),
    PRICE=tostring(price),
    EXPIRY_DATE='GTC',
    MARKET_STOP_LIMIT='NO',
    MARKET_TAKE_PROFIT='NO',
    IS_ACTIVE_IN_TIME='NO',
    OFFSET=tostring(offset),
    OFFSET_UNITS='PRICE_UNITS',
    STOPPRICE=tostring(dealprice), STOPPRICE2=tostring(stopprice),
    SPREAD=tostring(defspread),
    SPREAD_UNITS='PRICE_UNITS',
    COMMENT='TP_SL'
    })

    if err~="" then
    return nil, «AUTOMATIK_STOP_FUT результат: »..err
    else
    return trans_id, ""
    end
    end

    function OnCalculate(idx)
    if Zapusk then
    class=getDataSourceInfo().class_code
    sec=getDataSourceInfo().sec_code
    old_balance=get_balance(sec, Settings.client_code)
    Zapusk=false
    end
    if idx_prosl==idx then
    balance=get_balance(sec, Settings.client_code)
    if balance>0 and old_balance<balance then
    Sorder=false
    if old_balance<0 then
    spr_balance=balance
    else
    spr_balance=balance-old_balance
    end
    end
    if balance<0 and old_balance>balance then
    Sorder=false
    if old_balance>0 then
    spr_balance=0-balance
    else
    spr_balance=old_balance-balance
    end
    end
    if balance~=0 and not Sorder then
    Open_Price=get_latestprice(sec, Settings.client_code)
    if balance>0 and Open_Price~=0 then
    dealprice=Open_Price+Settings.profit --тейк
    stopprice=Open_Price-Settings.loss --стоп цена
    price=stopprice-Settings.loss_prosk --стоп с запасом
    offset=Settings.profit_otstup --отход от тейка
    defspread=Settings.profit_prosk --проск тейка
    Tr_Id,STR=TP_SL(class,sec,«S»,spr_balance,stopprice,price,dealprice,offset,defspread,nil,nil)
    Sorder=true
    if Tr_Id==nil then
    message(" "..STR,1)
    end
    end
    if balance<0 and Open_Price~=0 then
    dealprice=Open_Price-Settings.profit --тейк
    stopprice=Open_Price+Settings.loss --стоп цена
    price=stopprice+Settings.loss_prosk --стоп с запасом
    offset=Settings.profit_otstup --отход от тейка
    defspread=Settings.profit_prosk --проск тейка
    Tr_Id,STR=TP_SL(class,sec,«B»,spr_balance,stopprice,price,dealprice,offset,defspread,nil,nil)
    Sorder=true
    if Tr_Id==nil then
    message(" "..STR,1)
    end
    end
    end
    old_balance=get_balance(sec, Settings.client_code)
    end
    idx_prosl=idx
    return nil
    end

    рабочий вариант, и лучше в поля для пунктов выставлять десятичный вариант для примера, у меня не получилось его ввести с 0 по умолчанию

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

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