Избранное трейдера AntiKukl

по

Торговая система своими руками. Часть 3. Выставление заявок.

    • 05 сентября 2017, 14:48
    • |
    • k100
  • Еще

     Добрый день. В предыдущем посте были описаны базовые компоненты – классы обёртки над API брокера. Не хотелось нагружать их дополнительной логикой, поэтому оставим их как есть, и перейдём к чуть более сложному объекту. На сцене появляется IOrderManager, который отвечает за заявки и сделки по ним.

interface IOrderManager
{
   List<Order> GetOrders(string symbol, int strategyID);
   void PlaceOrder(string symbol, int strategyID, OrderAction action, OrderType type, double price, double amount, double stopPrice);
} 

     Всего два метода – выставить заявку и получить их список. Но, у реализации IOrderManager’а непростая задача – надо не просто выставлять заявки, но также хранить какая стратегия это сделала и какие прошли сделки. Получается, у OrderManager’а есть некое состояние – список заявок/сделок, поэтому этот объект относится больше к модели, чем к сервисному слою программы. Перед этим я описывал IPortfolioGate – класс-обёртка для работы с портфелем, вот у него нет состояния, он просто транслирует вызов методов внешней COM библиотеки, а вот OrderManager это некий дополнительный уровень над всем этим – у него появляются «знания» о предметной области, и именно он используется в классах стратегий.
     Также, появляются две сущности – заявка (Order) и сделка (Trade). Класс Order имеет список сделок прошедших по данной заявке.

class Order
{
   public string Symbol { get; set; }
   public OrderAction Action { get; set; }
   public double Price { get; set; }
   …
   public List<Trade> Trades { get; set; }
}


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

Торговая система своими руками. Часть 2. Базовые компоненты.

    • 01 сентября 2017, 11:36
    • |
    • k100
  • Еще

     Приветствую! В предыдущем посте была теория, теперь к делу. Кое-что буду упрощать, чтобы представить картинку в целом.

     Итак, чтобы проект не зависел от API внешней com библиотеки (SmartCom или д.р.), чтобы в коде стратегий  не использовались специфические типы, разработку я начала с обёрток над смарткомом. Я определил три базовых интерфейса: IConnectGate, IMarketDataGate и IPortfolioGate. Соответственно для подключения, для получения маркет-даты и для выставления заявок и работы с портфелем. Причём каждый из этих трёх интерфейсов мне надо было реализовать минимум дважды – для смарткома и для локального тестера.

     В случае со смарткомом, это некий адаптер-обёртка, благодаря которому, я оперирую собственными типами и не завишу от com библиотеки. Т.е. у меня есть свои типы (например, направление заявки, тайм-фрейм), которые используются в коде, а адаптер-обёртка конвертирует их в специфические, понятные внешней библиотеке. Также, желательно, чтобы у каждого объекта, в программе, была только одна обязанность, поэтому никакой дополнительной логики эти обёртки не несут.



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

Торговая система своими руками. Часть 1. Введение. MVP.

    • 29 августа 2017, 13:52
    • |
    • k100
  • Еще

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

   Даже такие проекты, как торговая система, требуют определённого подхода к структуре – проект разрастается со временем, хочется большего, и на это надо закладываться в самом начале. Даже, если система пишется под себя, не стоит уклоняться от  более формального подхода. Это, как ставить кубик на кубик — хорошая расстановка даст более прочную башню. Такие проекты справляются с увеличением сложности, новые изменения усиливают проект, в конце концов, такие проекты, способны перерасти во что-то более сложное (типа фазового перехода). А проекты с непродуманной архитектурой наоборот – со временем вносить изменения становится мучительнее и дороже, возрастают затраты на обслуживание, новые изменения ослабляют проект и он не способен перерасти во что-то более сложное. Но, сами понимаете, не всё так просто. Выбирая, каким будет проект, мы, опираясь на опыт, всё равно, угадываем направления развития.



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

Торговая система своими руками.

    • 25 августа 2017, 14:28
    • |
    • k100
  • Еще

Привет всем! Хотел опубликовать серию постов с описанием, как я на C# разработал систему для тестирования и торговли. Уклон будет больше в программирование, но в рамках алго.

Смысл в том, что я старался придерживаться правил ООП и сделать систему простой и конфигурируемой. В нескольких статьях я простыми словами расскажу про фишечки программирования, которые использовал. Расскажу про подходы к написанию объектно-ориентированного кода и про соответствующие библиотеки, которые использовал. Уделю внимание базам данных, как можно связываться с базами посредством объектно-реляционных преобразований  и про сам SQL. Опишу, что такое внедрение зависимостей и IoC контейнер, и как благодаря этому, только от одной переменной зависит режим работы – тестовый или торговый. Приведу пример реализации стратегии в рамках системы.
Оговорюсь, что это не hft – здесь не будет специальной оптимизации, работы с драйверами, памятью и т.д. В разработке использовал SmartCom и открытые библиотеки на C#. Чтобы не получилось слишком объёмно – буду сокращать, и опишу только часть моментов, опустив остальное (многопоточнось, проверки, защиту от сбоев и т.д.) Знаю, что есть StockSharp и пр. но… но… у меня с этим не пошло… мне проще оказалось сделать самому, чем от кого-то зависеть.

Оговорюсь так же, что всё нижесказанное – это моё личное мнение, сформированное в рамках моего понимания, не претендующее ни на что.  Я всё буду объяснять своими словами, и лишь хочу осветить тот материал, который здесь не обсуждался, либо обсуждался мало. В своё время, смарт-лаб очень много дал мне, что бы не говорили, это очень хороший ресурс, где много интересных людей! Я хочу внести и свою лепту в копилку, может кому-то, когда-нибудь пригодиться. Буду публиковать по одной – две статьи в неделю, всего будет 11 статей.



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

Валютный контроль

Еще до негативных новостей по Открытию запланировал открытие счета у дополнительного брокера (в целях диверсификации), предоставляющего доступ на Америку. Выбирал между БКС, Церихом и IB, но решение откладывал так как в каждом варианте были свои минусы.
Начало первых негативных новостей по Открытию, поспособствовали скорейшейму решению по выбору брокера. Остановился на IB. Открыл счет.
Далее необходимо было в течение 45 дней пополнить счет IB.
Так как хранить денежные средства (далее ДС) у Открытия считаю опасным, вывел ДС из Открытия, но оставил только акции (25% от портфеля). Планирую дальше работать с Открытием, но без свободных ДС на счете.

Так вот, вывод ДС происходил по следующей цепочке:
Открытие-75%ДС-Ситибанк-50%ДС-IB. Все ДС в USD.

В инете пишут чтобы транзакции проходили без внимания валютного контроля сумма перевода должна быть менее 600 тыс. руб. Я не захотел платить приличную сумму комиссий и решил перевести всю сумму одним переводом. Так как все ДС легальны сразу предоставил в банк все документы, а именно: копию договора с брокером, письмо от брокера об открытии счета, справки с места работы о средней ЗП, все справки 2НДФЛ от работодателя за 4 года работы, копию паспорта. Валютный контроль пропустил, перевод в IB выполнен, комиссия за перевод 150 USD.

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

Нефть и фьючерсная кривая

    • 01 августа 2017, 18:34
    • |
    • Zmey
  • Еще
Оригинал: http://zmey.club/opinion/153-neft-i-fyuchersnaya-krivaya.html

В последнее время отмечаю устойчивые изменения фьючерсной кривой по нефти. Дальние контракты дешевеют относительно цены спот и эта тенденция не уходит даже при падении котировок. По данным на 1 августа контракты с поставкой через один год (как по BRENT, так и по LIGHT) всё ещё торгуются в контанго, однако премия к спот-цене уже не покрывает даже текущей инфляции. Насколько это опасно для рынка нефти? Как это связано с котировками и стоит ли вообще делать какие-то выводы?
Нефть и фьючерсная кривая
Рисунок 1 — фьючерсная кривая по нефти LIGHT. 
Красная линия — спот-цена в долларах 2017-го года (левая шкала), 
синяя — значение индикатора (правая шкала).

Работать сразу со всей кривой в данном случае неудобно, поэтому вместо неё я использую только один индикатор — разницу в процентах между склеенными контрактами №14 и №2. По времени до истечения разница между ними равна одному году, что автоматически избавляет нас от сезонности; контракт №1 не участвует в расчётах, поскольку накануне экспирации часто «отклеивается» от фьючерсной кривой. Положительная разница соответствует торговле в контанго, отрицательная — в бэквардации.

Как видно из графиков (рисунки 1-2), описанный индикатор находится в тесной взаимосвязи с ценой — контанго всегда появляется на впадинах рынка, а бэквардация на вершинах. Мнения почему возникает например, бэквардация существуют самые разные (от обычных спекуляций до локального дефицита на физическом рынке), но все они ведут к общему выводу — производители считают цену завышенной. Да, именно производители, поскольку это они своим хеджем опускают дальние фьючерсы вниз.

Разумеется, что производители также иногда ошибаются и период времени с 2003-го по 2005-ой годы, когда бэквардация нисколько не препятствовала росту цены, наглядно иллюстрирует эту возможность. Наличие в истории подобного происшествия это явное указание на то, что кроме абсолютных значений индикатора нужно смотреть ещё и его динамику — истинная дороговизна нефти должна подтверждаться не только глухой бэквардацией, но и её увеличением по мере дальнейшего роста цены.

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

Обратный пропорциональный спред - мощь и красота

Для спецов в опционах сегодня я могу поделиться опытом использования обратного пропорционального спреда. За последнее время это наиболее популярная конструкция в моей торговле (направленная торговля опционами), и расскажу почему.

 

Обратный пропорциональный спред активно применяется мной по следующим причинам: по наблюдениям даёт хороший прирост цены (обычно выше, чем участвующие в нём опционы на его страйки по отдельности), а также хорош для управления позицией.

Не буду рассказывать теорию, а поделюсь практикой.

Вообще я читал в западных источниках, что такая конструкция подходит, когда вы ожидаете например резкий рост на БА, но его вероятность  — невысокая. Тогда типа покупай такую конструкцию за практически 0 – в случае роста цены на БА вы получаете хорошую прибыль, а если его не происходит – то цена опциона не меняется да и вы ничем не рисковали, в смысле не было ваших расходов. Например, это подходит для биотеха, если ждете прорыва у какой-то компании, выдачи разрешения FDA и т.п.



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

Код робота на 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

Мой доклад на конференции 20.05.17 в Челябинске

Мой доклад на конференции 20.05.17 в Челябинске

Введение

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

Мой доклад на конференции 20.05.17 в Челябинске



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

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