Блог им. _sk_

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

    • 10 февраля 2017, 15:11
    • |
    • _sk_
  • Еще
В некоторых торговых стратегиях используются цены нескольких активов. Скажем, можно торговать фьючерс 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


Удачи!
★53
18 комментариев
спасибо
avatar
идентификатор основного инструмента — это «security»? просто tag1= и tag2= понятно, а в скрипте основного нет)
avatar
ЛеПа, основной инструмент — это тот, который является источником данных для индикатора (на этот график добавляется индикатор). Дополнительные инструменты — это те, графики которых указаны в tag1, tag2.
avatar
_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 месяцев и более.»
Скажите пожалуйста, можно такой скрипт написать для КВИК? 
Я не умею. Можете помочь?

avatar
Samo, думаю, если спросите о таком на форуме квика
forum.quik.ru/forum10/
то кто-нибудь может возьмётся за такое за недорого.
Есть ли индекс доллара в квике — не знаю, т.к. мой брокер его не транслирует.
avatar
_sk_, здравствуйте! Не пойму, работает ли индикатор на QUIK 7.27.2.1. У меня не запускается.
avatar
спасибо!
Вот скрипт, вычмсляющий любую заданную функцию от двух графиков. Функция задается произвольным математическим выражением, включая вызовы функций.

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

avatar
Vkt, если поменять таймфрейм на всех графиках, индикатор будет работать на этом новом таймфрейме. Идентификаторы графиков можно не менять.
avatar
_sk_, это понятно, только не очень удобно если надо на  3-4-5 графиках ТФ туда-сюда менять. Не хватает пока функциональности QLua. В MQL4 такие задачи попроще решаются.
avatar
++++, плюс подписалась на Вас. жду подобные посты от Вас и впредь. до этого был у меня арбитраж индюк — 2 инструмена только, Ваш еще круче. )
avatar
Данный скрипт не идет у меня почему-то?
эээ… очень все крутые парни. А для пущей наглядности могли бы пару скринов кинуть по применению данного скрипта. Да и так чтобы было видно эти самые метки. Да пусть основной инструмент будет акции «Сбербанка». Пожалуйста. Мне очень хочется на примере разобраться.
avatar
данный скрипт имеет ошибку: "

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 ?

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

avatar
Квик версии 7.12.1.10  не видит индикатор.Подскажите что надо изменить?
avatar
 Все нормально, большое спасибо!
avatar
 Подскажите, может есть мысли, на macOS  почему может не работать? Под windows  все ок, спасибо.
avatar

теги блога _sk_

....все тэги



UPDONW
Новый дизайн