_sk_
_sk_ личный блог
10 февраля 2017, 15:11

Построение графика спреда в терминале QUIK

В некоторых торговых стратегиях используются цены нескольких активов. Скажем, можно торговать фьючерс MX, глядя на цены фьючерсов MX, SR GZ и выполняя над ними некоторые арифметические преобразования. Например, построить график вида
Spread := price(MX) — 5 * price(SR) — 5 * price(GZ) — 50000
по текущим котировкам и строить торговые идеи на его основе.

Кому интересна визуализация подобных спредов в терминале QUIK 7-й версии с помощью lua-скриптов, добро пожаловать под кат.

Будем считать, что у нас есть график основного инструмента (MXH7) и графики двух дополнительных инструментов (SRH7, GZH7). Эти графики уже построены в терминале, установлен одинаковый таймфрейм (скажем, 1 минута) и им даны идентификаторы MXH7_1min, SRH7_1min, GZH7_1min.

Создадим в папке установки терминала подпапку LuaIndicators и поместим туда скрипт SpreadIndicator.lua, приведённый в конце поста (выделите код, скопируйте в блокнот и сохраните в файл с указанным именем). Добавим на график MXH7 индикатор «SpreadIndicator» и зададим ему параметры:
  • tag1 — метка графика, откуда берётся цена дополнительного инструмента 1 (в нашем случае SRH7_1min);
  • tag2 — метка графика, откуда берётся цена дополнительного инструмента 2 (в нашем случае GZH7_1min);
  • коэффициенты k, k1, k2, a, по которым вычисляется спред spread.
Формула для вычисления спреда такова: spread := k * price(security) + k1 * price(tag1) + k2 * price(tag2) + a.

График спреда будет обновляться при обновлении графика основного инструмента.

Код несложно модифицировать для случая другого количества инструментов и формулы для расчёта спреда (см. функцию getSpread). Это хорошее упражнение для повышения Вашего уровня владения навыками программирования на lua.

--
-- Построение спреда по нескольким инструментам:
-- spread := k * price(security) + k1 * price(tag1) + k2 * price(tag2) + a.
-- Можно добавлять дополнительные инструменты, модифицируя код индикатора.
--

Settings = {
    Name = "SpreadIndicator",
    k = 1, -- коэффициент, с которым учитывается цена основного инструмента
    tag1 = "SRH7_1min", -- метка графика, откуда берётся цена дополнительного инструмента 1
    tag2 = "GZH7_1min", -- метка графика, откуда берётся цена дополнительного инструмента 2
    k1 = -5, -- коэффициент, с которым учитывается цена дополнительного инструмента 1
    k2 = -5, -- коэффициент, с которым учитывается цена дополнительного инструмента 2
    a = 0, -- свободный член
    line = { { Name = "Spread", Color = RGB(0, 0, 255), Type = TYPE_LINE, Width = 1, } }
}

function Init()
    return 1
end

local function getTimeCode(dt)
    return (dt.year * 10000 + dt.month * 100 + dt.day) * 1000000 + (dt.hour * 10000 + dt.min * 100 + dt.sec)
end

--- Найти свечу, относящуюся к заданному времени или предшествующую ему, если для заданного времени нет свечи.
-- @param tag строковый идентификатор графика или индикатора
-- @param timeCode метка времени в формате yyyymmddhhmmss
-- @return искомая свеча или nil, если свеча не найдена.
local function getCandleByTimeCode(tag, timeCode)
    local numCandles = getNumCandles(tag)
    if numCandles < 2 then
        return nil
    end
    local lastCandle, n, _ = getCandlesByIndex(tag, 0, numCandles - 1, 1)
    if n ~= 1 then
        return nil
    end
    lastCandle = lastCandle[0]
    if getTimeCode(lastCandle.datetime) <= timeCode then
        return lastCandle
    end
    local b = numCandles - 1
    local a = b - 1
    local candle
    while true do
        local firstCandle, n, _ = getCandlesByIndex(tag, 0, a, 1)
        if n ~= 1 then
            return nil
        end
        firstCandle = firstCandle[0]
        local firstTimeCode = getTimeCode(firstCandle.datetime)
        if firstTimeCode == timeCode then
            return firstCandle
        elseif firstTimeCode < timeCode then
            candle = firstCandle
            break
        elseif a == 0 then
            return nil
        else
            a = math.max(0, 2 * a - b)
        end
    end
    while true do
        local c = math.floor((a + b) / 2)
        if c == a then
            return candle
        else
            local middleCandle, n, _ = getCandlesByIndex(tag, 0, c, 1)
            if n ~= 1 then
                return nil
            end
            middleCandle = middleCandle[0]
            local middleTimeCode = getTimeCode(middleCandle.datetime)
            if middleTimeCode == timeCode then
                return middleCandle
            elseif middleTimeCode < timeCode then
                a, candle = c, middleCandle
            else
                b = c
            end
        end
    end
end

--- Вычислить спред.
-- @param index номер свечи на графике
-- @return значение спреда или nil, если оно неопределено
local function getSpread(index)
    local timeCode = getTimeCode(T(index))
    local securityPrice = C(index)
    if securityPrice == nil then
        return nil
    end
    -- Получение свечей дополнительных инструментов
    local candle1 = getCandleByTimeCode(Settings.tag1, timeCode)
    local candle2 = getCandleByTimeCode(Settings.tag2, timeCode)
    if candle1 == nil or candle2 == nil then
        return nil
    end
    -- Получение цен дополнительных инструментов
    local price1 = candle1.close
    local price2 = candle2.close
    if price1 == nil or price2 == nil then
        return nil
    end
    -- Вычисление спреда
    local spread = Settings.k * securityPrice
            + Settings.k1 * price1
            + Settings.k2 * price2
            + Settings.a
    return spread
end

function OnCalculate(index)
    if index > 1 then
        local spread = getSpread(index - 1)
        if spread then
            SetValue(index - 1, 0, spread)
        end
    end
    return getSpread(index)
end


Удачи!
18 Комментариев
  • Фыва
    10 февраля 2017, 15:20
    спасибо
  • ЛеПа
    10 февраля 2017, 15:36
    идентификатор основного инструмента — это «security»? просто tag1= и tag2= понятно, а в скрипте основного нет)
      • Samo
        23 февраля 2019, 22:02
        _sk_, приветствую вас. очень заинтересовала тема. 
        Ниже приведу слова Ларри Вильямса:

        «Золото может расти быстрее доллара США только до тех пор, пока оно не начнет падать. Эту взаимосвязь трудно увидеть, рассматривая графики, но вовсе не трудно обнаружить, когда вы посмотрите на взаимосвязь спрэда между этими рынками. Для обнаружения взаимосвязи, на которую мне нравиться смотреть, нужно взять недельный спрэд между этими двумя рынками, затем построить трехнедельное скользящее среднее и 21-недельное скользящее среднее этого спрэда. Чтобы увидеть маятниковые колебания рассматриваемого спреда, я вычитаю далее трехнедельное скользящее среднее из 21-недельного скользящего среднего. Деление полученного результата на 100 дает нам равномерный распределенный коэффицент; таким образом при подходящем масштабе можно увидеть любой момент времени. Проделывая эти вычисления, я заметил, что когда данный коэффициент переходит через край, т.е. когда отношение трехнедельного к 21-недельному спреду превышает 30%, то на рынке золота вскоре обнаруживается спад. Иными словами, золото может оказаться перекупленным по отношению к доллару США, и в этот момент времени крупные суммы денег профессионалов выходят на рынок, чтобы воспользоваться указанными дисбалансом путем продажи золота».
        На просторах интернета нашел такой индикатор, но он для МТ4 и 5.
        Вот пример:
        «Из сказанного выше, можно получить формулу расчета этого инидкатора:

        (SMA 21(IndexDollar-Gold) – SMA 3 (IndexDollar-Gold))/100

        где:

                   SMA 21 — 21-периодичное простое скользящее среднее

                   SMA 3 — трехнедельное простое скользящее среднее

                   IndexDollar — индекс доллара

                   Gold – золото

        ВАЖНОЕ ЗАМЕЧАНИЕ: это исключительно долгосрочный индикатор, лучше всего его использовать на недельных таймфреймах. Его задача указывать на будущие движения длящиеся 6 месяцев и более.»
        Скажите пожалуйста, можно такой скрипт написать для КВИК? 
        Я не умею. Можете помочь?

      • DimaS_EKB
        23 декабря 2022, 10:02
        _sk_, здравствуйте! Не пойму, работает ли индикатор на QUIK 7.27.2.1. У меня не запускается.
  • Евгений Гуревич
    10 февраля 2017, 17:01
    спасибо!
  • s_mike@rambler.ru
    10 февраля 2017, 17:22
    Вот скрипт, вычмсляющий любую заданную функцию от двух графиков. Функция задается произвольным математическим выражением, включая вызовы функций.

    www.bot4sale.ru/download-categories/2012-06-13-15-10-36/item/juggler.html
  • Vkt
    10 февраля 2017, 18:28
    Все здорово, жаль только что график спреда привязан к одному ТФ.

      • Vkt
        10 февраля 2017, 20:32
        _sk_, это понятно, только не очень удобно если надо на  3-4-5 графиках ТФ туда-сюда менять. Не хватает пока функциональности QLua. В MQL4 такие задачи попроще решаются.
  • ЛеПа
    11 февраля 2017, 13:21
    ++++, плюс подписалась на Вас. жду подобные посты от Вас и впредь. до этого был у меня арбитраж индюк — 2 инструмена только, Ваш еще круче. )
  • Андрей Петров
    04 марта 2017, 18:16
    Данный скрипт не идет у меня почему-то?
  • Evgeny Grizli
    26 июля 2017, 13:59
    эээ… очень все крутые парни. А для пущей наглядности могли бы пару скринов кинуть по применению данного скрипта. Да и так чтобы было видно эти самые метки. Да пусть основной инструмент будет акции «Сбербанка». Пожалуйста. Мне очень хочется на примере разобраться.
  • Evgeny Grizli
    26 июля 2017, 15:33
    данный скрипт имеет ошибку: "

    lua: spread_ind_1.lua:15: attempt to call global 'RGB' (a nil value)
    stack traceback:
    spread_ind_1.lua:15: in main chunk
    [C]: in ?

     "
    Может кто-то объяснит?

  • echaki
    26 июля 2017, 18:06
    Квик версии 7.12.1.10  не видит индикатор.Подскажите что надо изменить?
  • echaki
    27 июля 2017, 09:47
     Все нормально, большое спасибо!
  • Герман
    03 октября 2017, 10:37
     Подскажите, может есть мысли, на macOS  почему может не работать? Под windows  все ок, спасибо.

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

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