_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= понятно, а в скрипте основного нет)
  • Евгений Гуревич
    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

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

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