Избранное трейдера Petr S

по

Торговая стратегия для коинтегрированных пар: результаты бэктестов за 2017 год на Мосбирже

В данном блог-посте будет представлена простейшая стратегия статистического арбитража, основанная на торговле коинтегрированными парами акций, которые были выявлены на Московской бирже, а также результаты бэктестов по ней.

Торговая стратегия

Допустим, у нас есть коинтегрированная пара акций, X и Y, а также цены этих акций за некий период времени 0,...,T. Для примера возьмём пару акций с тикерами (MSNG,MRSB). Для неё у нас есть данные о ценах за 252 торговых дня.

Первую половину наблюдений мы будем использовать, чтобы определить параметры торговой стратегии. Затем, основываясь на найденных параметрах, мы возьмём вторую половину наблюдений и проведём бэктесты, то есть протестируем, принесёт ли нам такая стратегия деньги.

Для дальнейших рассуждений нам понадобится спред двух акций. В нашем примере с парой (MSNG,MRSB) мы уже находили спред в блог-посте про коинтеграцию, так что здесь я просто продублирую картинку.


( Читать дальше )

Автологин в QUIK (на Lua).

    • 12 января 2018, 17:57
    • |
    • XXM
  • Еще

Узнал, что продается робот на Lua, «Автологин терминала QUIK».
Продается то, что есть в открытом виде на quik2dde.ru  

Выкладываю тут: 

-- quik_login.lua
-- Автологин терминала QUIK
-- © http://qui2dde.ru/
-- Версия: 2.0
-- для Quik от версии 7.11.1.5

local w32 = require("w32")

-- логин и пароль для терминала
QUIK_LOGIN = "Uxxxxxxx"
QUIK_PASSW = "yyyyy"

function FindLoginWindow()
  hLoginWnd = w32.FindWindow("", "Идентификация пользователя")
  if hLoginWnd == 0 then
    hLoginWnd = w32.FindWindow("", "User identification")
  end
  return hLoginWnd
end

timeout = 1000  -- таймаут между попытками поиска окна логина
is_run = true

function OnStop()
  timeout = 1
  is_run = false
end

function main()
  while is_run do
    sleep(timeout)

    if isConnected() == 0 then
  
      local hLoginWnd = FindLoginWindow()
      if hLoginWnd ~= 0 then

        local n1 = w32.FindWindowEx(hLoginWnd, 0, "", "")
        local n2 = w32.FindWindowEx(hLoginWnd, n1, "", "")
        local n3 = w32.FindWindowEx(hLoginWnd, n2, "", "")
        local n4 = w32.FindWindowEx(hLoginWnd, n3, "", "")

        w32.SetWindowText(n2, QUIK_LOGIN)
        w32.SetWindowText(n3, QUIK_PASSW)


        w32.SetFocus(n4)
        w32.PostMessage(n4, w32.BM_CLICK, 0, 0)

      end 
    end

  end
end
Благодарности, как понимаю, следует адресовать swerg  
  • обсудить на форуме:
  • QUIK

Инфографика. Диаграмма рыночного цикла.

Инфографика. Диаграмма рыночного цикла.

Накопление: происходит после падения цен. Процесс приобретения покупателями контроля со стороны продавцов, что приводит к разметке.

Подъем: бычья фаза жизни акции определяется более высокими максимумами и более высокими минимумами. Это то место, где вы хотите получить долго на прорывы и после краткосрочных откатов. 

Распространение: происходит после продолжительного роста цен. Продавцы получают контроль над ценами, что приводит к снижению.

Упадок: Медвежья фаза жизни акции. 


US Treasuries- и другие мысли по рынку.

Это год, когда центральные банки переобуются !

Надеюсь, что это год будет хорошим для вас, и я даже думаю что он будет самым лучшим. Сейчас самое время, чтобы сделать прогноз на будущие 12 месяцев. Мой прогноз будет самым реальным и очевидным в 2018 году. Слишком много чего произойдет в 2018 году и будущие тренды ожидаемы.

Сейчас конечно идет бум связанный с крипто валютами и весь smart-lab просто напичкан постами о идеях развития этого инструмента, но я начну с невероятно скучного класса актива: US Treasuries, это класс активов, в котором я наиболее оптимистичен, или скажу так: это место где я вижу хорошие шансы заработать деньги в этом году, и позвольте вам донести мою идею.

Первый график – это 30 и 10 летние казначейские ставки США

QE – программа смягчения  / QT – программа ужесточения.
US Treasuries- и другие мысли по рынку.

Я постоянно говорил, что QE постоянно увеличивала доходность на облигациях, а не снижала, как обычно полагали. Таким образом, QT (программа ужесточения) должна снижать, а не повышать доходность.



( Читать дальше )

Начал изучать Python

Прочитал книжку Think Python: How to Think Like a Computer Scientist — очень понравилась: вместо сухого изложения с самого начала рассматриваются маленькие программы, которые в последующих главах дорабатываются с учетом более продвинутых концепций языка. Почти в каждой главе даются подходы, которые применяются при разработке и отладке больших по объёму программ. Даны основы data science — быстродействие различных структур данных, как организована их работа под капотом и т.д.

До прочтения написал программу строк на 200 про отслеживание диеты, которая представляла мало понятный кусок кода. После прочтения книги переписал в 100 строк.

Автор понравился, поэтому на очереди Think Complexity: Complexity Science and Computational Modeling. По планам к январю хочу поднабраться знаний и приступить к автоматизации торговой системы на  Python.


Опционы для Гениев (экспорт волатильности)

В одной из своих лекций Кирилл Ильинский рассказывал про экспорт волатильности. В свою бытность он работал толи в ГолдманСаксе, толи в банке каком то (в Альпари точно не работал) и любил от туда Родину. И вот он предложил руководству покупать волатильность в России и продавать ее в штатах. Дело в том, что дески в штатах работают немного на опережение и по всякому поводу задирают волатильность. А дески в России, тогда под управлением Калинковича, ведут себя более взвешено и определяют волатильность по факту. Я не знаю, почему тогда не срослась схема. Возможно, не хватало ликвидности. И если бы даже Каленкович продал свою машину, то этих объемов не хватило бы, что бы заинтересовать Голдмана.  

Тем не менее, схема не могла пройти мимо искателей легкой наживы. Так Борис Журавлев опубликовал и даже снял видео про данную стратегию  http://www.optionlaboratory.ru/load/video_materialy/opcionnyj_arbitrazh_moskva_chikago/1-1-0-37

Даже на сегодня она имеет право на жизнь. Действительно волатильность RSX выше волатильности РТС. И мы можем продавать ее в штатах, а покупать в России. Таким образом осуществлять экспорт волатильности, причем мимо таможни, что очень радует. А еще мы покупаем за рубли, а продаем за валюту. Любой Газпром об этом мог только мечтать.



( Читать дальше )

Что купить, а что не стоит!? Несколько мыслей

Большинство ожиданий со вчерашнего дня пока оправдалось - https://smart-lab.ru/blog/431302.php
Сегодня следующие мысли.  В целом ситуация остается прежней, из интересного по среднесроку как мне видится:
Золото делает более уверенную попытку начать рост, следим внимательно делаем первые попытки покупать!
Что купить, а что не стоит!? Несколько мыслей
Нефть могут слить, кто-то сильно вчера отлил цену от хаёв, наверное волна роста заканчивается или развернем или боковик.
Сургутнефтегаз хорошо вышел наверх, объёмы благоприятно снизились, а движение все также активно, вероятен хороший рост в ближайшее время.
Что купить, а что не стоит!? Несколько мыслей

( Читать дальше )

Торговая система своими руками. Часть 10. IoC, защита от сбоев, логгирование.

    • 26 октября 2017, 12:32
    • |
    • k100
  • Еще

     Привет всем! В предыдущих статьях я описывал свой тестер, разработанный на C#, и, несколько раз подчёркивал, что переключение между двумя режимами (тестирование/торговля) может быть простым. Код стратегий не должен зависеть от того, кто поставщик маркет-даты и куда уходят заявки – в тестовую базу или на сервер брокера. Конечно, это лишь один из подходов, и кому-то он покажется странным, но, главное его достоинство заключается в том, что тестирование приближается к реальности, что даёт более достоверные результаты. Вопрос в следующем: как, имея один и тот же код, получать разные по функциональности программы? Один из вариантов – использовать инверсию управления и внедрение зависимостей! Об этом сегодня и пойдёт речь.

    Приведу пример нехорошего (иногда, говорят – с запашком) кода:

class Strategy
{
   public Strategy()
   {
     var mgr = new TestOrderManadger();
     mgr.PlaceOrder(...);
   }
}

     Здесь плохо то, что класс Strategy зависит от класса TestOrderManadger. В такой реализации нельзя начать использовать какой-нибудь другой менеджер заявок (AnotherOrderManadger) без перекомпиляции библиотеки с классом Strategy. Тем более тут нарушается принцип единства ответственности – класс Strategy, помимо своей прямой обязанности, также, создаёт внутри себя зависимости. Чтобы исправить ситуацию, можно использовать интерфейсы:

interface IOrderMandger
{
   void PlaceOrder();
}

class TestOrderManadger : IOrderMandger
{
   public void PlaceOrder(){}
}

class Strategy
{
   public Strategy(IOrderMandger orderMandger)
   {
     var mgr = orderMandger;
     mgr.PlaceOrder(...);
   }
}


( Читать дальше )

Код робота на LUA для QUIK

В двух словах: робот анализирует спот, выставляет лимитные и стоп-лимитные заявки по фьючерсу. Делает пересчет сигналов по выбранному тайм-фрейму, снятие выставленных заявок, запись в файл текущего состояния, ведение логов, сообщения, запрос текущей позиции и пр. Из робота удалена алгоритмика вычисления сигнала и в текущем виде скрипт будет иметь сигнал на покупку на каждом баре.

Предназначается для новичков в алготрейдинге, что-то типа болванки.

Важно: выставление заявок я закомментировал, поэтому можете смело запускать этот скрит, он не натворит ужаса по счету.

require"QL"

log = "sbrf.log"
seccode = "SRM6"
lots_in_trade = 80
accnt = ""
better = -5
chart = "sberbankxxx"
is_run = true
prev_datetime = {}
len = 100
basis = 9
k_bal = {0,1,2,3}
sell = false
buy = false
id = 0
first = true

function trade_signal(shift)
        number_of_candles = getNumCandles(chart)
        bars_temp,res,legend = getCandlesByIndex(chart,0,number_of_candles-2*len-shift,2*len)
        bars={}

        i=len
        j=2*len
        while i>=1 do
                if bars_temp[j-1].datetime.hour>=10 then
                        sk=true
                        if bars_temp[j-1].datetime.hour==18 and bars_temp[j-1].datetime.min==45 then
                                sk=false
                        end
                        if sk then
                                bars[i]=bars_temp[j-1]
                                i=i-1
                        end
                end
                j=j-1
        end

        t = len+1

        do_sell = false
        do_buy = true

        value = 0
        if do_sell then value = 1 end
        if do_buy then value = -1 end
        toLog(log,"value="..value.." on candle: "..bars[len].datetime.year.."-"..bars[len].datetime.month.."-"..bars[len].datetime.day.." "..bars[len].datetime.hour..":"..bars[len].datetime.min.."   O="..bars[len].open.." H="..bars[len].high.." L="..bars[len].low.." C="..bars[len].close.." V="..bars[len].volume)
        return value
end

function mysplit(inputstr, sep)
        if sep == nil then
                sep = "%s"
        end
        local t={} ; i=1
        for str in string.gmatch(inputstr, "([^"..sep.."]+)") do
                t[i] = str
                i = i + 1
        end
        return t
end

function OnInit(path)
        log=getScriptPath()..'\\'..log
        toLog(log,"==========OnInit: START")
        toLog(log,"==========OnInit: FINISH")
end

function OnStop()
        is_run = false
        toLog(log,"==========OnStop: script finished manually")
end

function CheckBit(flags, bit)
   -- Проверяет, что переданные аргументы являются числами
   if type(flags) ~= "number" then error("Ошибка!!! Checkbit: 1-й аргумент не число!"); end;
   if type(bit) ~= "number" then error("Ошибка!!! Checkbit: 2-й аргумент не число!"); end;
   local RevBitsStr  = ""; -- Перевернутое (задом наперед) строковое представление двоичного представления переданного десятичного числа (flags)
   local Fmod = 0; -- Остаток от деления
   local Go = true; -- Флаг работы цикла
   while Go do
      Fmod = math.fmod(flags, 2); -- Остаток от деления
      flags = math.floor(flags/2); -- Оставляет для следующей итерации цикла только целую часть от деления
      RevBitsStr = RevBitsStr ..tostring(Fmod); -- Добавляет справа остаток от деления
      if flags == 0 then Go = false; end; -- Если был последний бит, завершает цикл
   end;
   -- Возвращает значение бита
   local Result = RevBitsStr :sub(bit+1,bit+1);
   if Result == "0" then return 0;
   elseif Result == "1" then return 1;
   else return nil;
   end;
end;

function killorders(ccode,scode)
    for i=0,getNumberOf("orders")-1,1 do
        local t=getItem("orders", i)
        if t ~= nil and type(t) == "table" then
            if( t.seccode == scode and CheckBit(t.flags, 0) == 1) then
                local transaction={
                    ["TRANS_ID"]=tostring(math.random(2000000000)),
                    ["ACTION"]="KILL_ORDER",
                    ["CLASSCODE"]=ccode,
                    ["SECCODE"]=scode,
                                        ["ACCOUNT"] = accnt,
                    ["ORDER_KEY"]=tostring(t.ordernum),
                }
                                res=sendTransaction(transaction)
            end
        end
    end
end

function killstoporders(ccode,scode)
    for i=0,getNumberOf("stop_orders")-1,1 do
        local t=getItem("stop_orders", i)
        if t ~= nil and type(t) == "table" then
            if( t.seccode == scode and CheckBit(t.flags, 0) == 1) then
                local transaction={
                    ["TRANS_ID"]=tostring(math.random(2000000000)),
                    ["ACTION"]="KILL_STOP_ORDER",
                    ["CLASSCODE"]=ccode,
                    ["SECCODE"]=scode,
                                        ["ACCOUNT"] = accnt,
                    ["STOP_ORDER_KEY"]=tostring(t.ordernum),
                }
                                res=sendTransaction(transaction)
            end
        end
    end
end


function main()
        toLog(log,"==========main: START")
        while is_run do
                if isConnected() == 1 then
                        ss = getInfoParam("SERVERTIME")
                        if string.len(ss) >= 5 then
                                hh = mysplit(ss,":")
                                str=hh[1]..hh[2]
                                h = tonumber(str)
                                if (h>=1000 and h<1400) or (h>=1405 and h<1845) or (h>=1905 and h<2350) then
                                        if first then
                                                for ti = 50,2,-1 do     trade_signal(ti) end
                                                if buy and not sell then message(seccode.." Current state: green and buy",1) end
                                                if sell and not buy then message(seccode.." Current state: red and sell",1) end
                                                if buy and sell then message(seccode.." ERROR: green and red",1) end
                                                if not buy and not sell then message(seccode.." WARNING: nothing",1) end
                                                first = false
                                        end
                                        prev_candle = getPrevCandle(chart,0)
                                        if not isEqual(prev_candle.datetime,prev_datetime) then
                                                current_value = trade_signal(1)

                                                if current_value ~= 0 then
                                                        optn = "B"
                                                        if current_value==1 then optn = "S" end
                                                        curvol=0
                                                        no=getNumberOf("FUTURES_CLIENT_HOLDING")
                                                        if no>0 then
                                                                for i=0,no-1,1 do
                                                                        im=getItem("FUTURES_CLIENT_HOLDING", i)
                                                                        if im.sec_code==seccode then
                                                                        curvol=im.totalnet
                                                                        end
                                                                end
                                                        end
                                                        trvol = -current_value*lots_in_trade-curvol
                                                        if trvol ~= 0 then
                                                                killorders("SPBFUT",seccode)
                                                                killstoporders("SPBFUT",seccode)
                                                                f = io.open(getScriptPath().."\\sbrf2_pos.txt","r")
                                                                sbrf2_pos=f:read("*n")
                                                                f:close()
                                                                f = io.open(getScriptPath().."\\sbrf3_pos.txt","r")
                                                                sbrf3_pos=f:read("*n")
                                                                f:close()
                                                                pr,n,l = getCandlesByIndex ("futsber", 0, getNumCandles("futsber")-1, 1)
                                                                local trans =
                                                                {
                                                                        ["ACTION"] = "NEW_ORDER",
                                                                        ["CLASSCODE"] = "SPBFUT",
                                                                        ["SECCODE"] = seccode,
                                                                        ["ACCOUNT"] = accnt,
                                                                        ["OPERATION"] = optn,
                                                                        ["PRICE"] = toPrice(seccode,pr[0].close+current_value*better),
                                                                        ["QUANTITY"] = tostring(math.abs(curvol-sbrf2_pos-sbrf3_pos)),
                                                                        ["TRANS_ID"] = tostring(getTradeDate().month*100+getTradeDate().day+id)
                                                                }
                                                                id = id+1
                                                                --res = sendTransaction(trans)
                                                                message(seccode.." Send : " .. res, 2)
                                                                toLog(log,"Send: ".. res)
                                                                for btr=0,200,5 do
                                                                        local trans =
                                                                        {
                                                                                ["ACTION"] = "NEW_STOP_ORDER",
                                                                                ["CLASSCODE"] = "SPBFUT",
                                                                                ["SECCODE"] = seccode,
                                                                                ["ACCOUNT"] = accnt,
                                                                                ["OPERATION"] = optn,
                                                                                ["PRICE"] = toPrice(seccode,pr[0].close-current_value*btr),
                                                                                ["STOPPRICE"] = toPrice(seccode,pr[0].close-current_value*(btr+better)),
                                                                                ["QUANTITY"] = tostring(6),
                                                                                ["TRANS_ID"] = tostring(getTradeDate().month*100+getTradeDate().day+id),
                                                                                ["EXPIRY_DATE"] = "GTC"
                                                                        }
                                                                        id = id+1
                                                                        --res = sendTransaction(trans)
                                                                        message(seccode.." Send : " .. res, 2)
                                                                        toLog(log,"Send: ".. res)
                                                                end
                                                                if current_value == 1 then
                                                                        message(seccode..' RED: buy->sell',1)
                                                                        toLog(log,"RED signal")
                                                                else
                                                                        message(seccode..' GREEN: sell->buy',1)
                                                                        toLog(log,"GREEN signal")
                                                                end
                                                        else
                                                                if current_value == 1 then
                                                                        message(seccode..' RED: buy->sell',1)
                                                                        toLog(log,"RED signal, but nothing to do")
                                                                else
                                                                        message(seccode..' GREEN: sell->buy',1)
                                                                        toLog(log,"GREEN signal, but nothing to do")
                                                                end
                                                        end
                                                else
                                                        if buy and not sell then toLog(log,"Nothing to do. Current state: green and buy",1) end
                                                        if sell and not buy then toLog(log,"Nothing to do. Current state: red and sell",1) end
                                                        if buy and sell then toLog(log,"Nothing to do. ERROR: green and red",1) end
                                                        if not buy and not sell then toLog(log,"Nothing to do. WARNING: nothing",1) end
                                                end
                                                prev_datetime = prev_candle.datetime
                                        end
                                end
                        end
                end
                sleep(5*1000)
        end
        toLog(log,"==========main: FINISH")
end
  • обсудить на форуме:
  • Quik Lua

....все тэги
UPDONW
Новый дизайн