Избранное трейдера MrD
Вчера появился пост с вопросом, что же за сделки происходят в голубых акциях, когда торги закончились. Что за глюки, мол.
Я попробую пояснить, и если в чем-то окажусь неточным, надеюсь, меня поправят более понимающие в этом товарищи.
В 18:40 заканчивается торговый период сессии и проходит его последняя сделка.
Наступает аукцион закрытия, который идет 10 минут.
Первые пять минут – до 18:45 – происходит аукционное определение цены закрытия сессии, и еще 5 минут по этой и только по этой цене могут пройти дополнительные сделки.
Как это происходит
Наступает 18:40 по мск, все заявки, выставленные игроками в торговый период, и которые защищали рынок от резких ложных движений, исчезают, появляются заявки людей, которые решили принять участие в аукционе.
В стакане становятся видны те заявки, которые попадают в 10-ку лучших заявок на продажу и покупку соответственно, остальные заявки не отражаются.
Использую торговую систему, реализованную на базе Excel. Возникла идея, изучить Питон и переписать системку на его основе. В связи с этим пару вопросов:
Settings= { Name = "Piton", N = 100, legend = "price2", line = { { Name = "Sint", Color = RGB(0, 132, 0), Type = TYPE_LINE, Width = 1 } } } function Init() return 1 end Candles = {}; function OnCalculate(index) local numCandles = getNumCandles(Settings.legend); if index <= Settings.N or numCandles <= Settings.N then return nil; end Candles, n, _ = getCandlesByIndex(Settings.legend, 0, index - Settings.N, Settings.N); if n ~= Settings.N then return nil; end -- Предварительный расчет sum1, sum2, sum3 = advancePaynemt(index); -- расчет коэффициента корреляции Пирсона r = sum3/math.sqrt(sum1*sum2); return r; end -- Предварительный расчет ---------------------------------------- function advancePaynemt(index) local sum1 = 0; local sum2 = 0; local sum3 = 0; local j = 0; -- Вычислить среднее арифметическое for i=index - Settings.N + 1, index, 1 do sum1 = sum1 + C(i); sum2 = sum2 + Candles[j].close; j = j + 1; end aver1 = sum1/Settings.N; aver2 = sum2/Settings.N; -- Вычислить сумму квадратов отклонений sum1 = 0; sum2 = 0; j = 0; for i=index - Settings.N+1, index, 1 do sum1 = sum1 + math.pow(C(i) - aver1, 2); sum2 = sum2 + math.pow(Candles[j].close - aver2, 2); j = j + 1; end -- Вычислить сумму произведений разности j=0; for i=index - Settings.N+1, index, 1 do sum3 = sum3 + (aver1 - C(i))*(aver2 - Candles[j].close); j = j + 1; end return sum1, sum2, sum3; endКак запустить и настроить:
Как я обещала, я собрала информацию об инвестиционном вычете (у него три подвида) и представляю ее в форме таблицы, чтобы было удобно смотреть.
Добрый день всем!
Такое ощущение, что визуально таблица не вся помещается. Кому неудобно смотреть таблицу, ниже идет картинками информация...
|
Положительный финансовый результат от продажи (погашении) ценных бумаг |
Сумма, внесенная на ИИС, но не более 400 тыс.руб. в год |
Положительный финансовый результат, полученный по операциям на ИИС |
Условия получения вычета |
1. Ценные бумаги находились в собственности более трех лет; 2. Ценные бумаги были приобретены с 02.01.2014 года; 3. Ценные бумаги обращаются на ОРЦБ; 4. Вы являетесь налоговым резидентом в том календарном году, в котором вы получили доход от продажи; |
Перевод статьи из блога tr8dr, кое-что из основ для HFT торговли.
Алгоритмы высокочастотной торговли можно разделить на следующие категории:
1. Различные формы маркет мэйкинга (вероятно самый большой процент)
2. Заработок на действиях других участников рынка или на микроструктуре рынка
3. Краткосрочный арбитраж
4. Алгоритмы исполнения больших заявок
Также среднесрочные стратегии подразделяются на:
1. Следование за трендом (если есть достаточно сильный импульс)
2. Следование за циклами (продажа/покупка в точках разворота высокоамплитудных ценовых циклов)
3. Долгосрочный арбитраж
Если сфокусироваться на алгоритмах маркет мэйкинга и следования тренду/циклам, то понимание ценового режима и ценовой функции очень важно.
Режим
Мы должны определять текущий ценовой режим для того, чтобы понимать, где мы можем применять стратегию маркет мэйкинга, а где следование тренду или циклам.
Изначально, была мысль написать большую статью, с множеством забавных эпизодов, прекрасно иллюстрированную. Но, честно, не осилил. Не нашел как верно отобразить графическую информацию. Поэтому, полагаюсь на то, что заинтересованные — сами проверят все описанные методы и оставят один-два комментария.
Рассмотрим разные варианты управления капиталом при торговле портфелем стратегий.
Для простоты, можно рассматривать портфель из двух стратегий, на отрезке где одна стратегия стабильно зарабатывает, а вторая работает неустойчиво.
1. Фиксированный лот без реинвестирования. Просто суммируем две кривые прироста капитала. В данном случае все просто, одна стратегия делает прибыль, другая добавляет просадки. При раздельном тестировании этот метод позволяет наиболее точно оценить стратегию. Минус метода в том, что при значительном изменении капитала (вывод или занос денег) нужно править рабочий обьем.
2. Каждой стратегии выделяется равный процент депозита, прибыль реинвестируется, либо уменьшается обьем при просадке счета
Тут вроде все понятно, этот подход все любят. На прибыль добавляемся, при убытке сокращаем лот. Если одна стратегия сильно льет, а вторая немного зарабатывает, то рабочий обьем режется на всех стратегиях, так как общий размер депозита сокращается. И тут возникает вариант 3, про который почему-то никто не говорит.
3. Создаем условия, когда каждая стратегия работает независимо (одна стратегия — один счет, стартовая сумма для счетов одинаковая), прибыль реинвестируется, либо уменьшается обьем при просадке счета. При этом каждое направление входа системы (лонг или шорт) рассматривается как отдельно взятая стратегия. Почему так? Возьмем простую трендследящую стратегию. На тренде вверх имеем хорошие сделки от лонга, но на резких и коротких коррекциях тренда шорт как правило не зарабатывает. И наоборот для тренда вниз. В этом случае мы будем резать лот на убыточном направлении стратегии и добавлять на прибыльном.
4. Доработка варианта 3. К каждой отдельно взятой стратегии добавляем элемент equity-trading. В коде стратегии отслеживаем изменение капитала (start_deposit +- netprofit), параллельно заполняем массив финансового результата при торговле 1 лотом, вводим порог допустимой просадки и при ее достижении выключаем стратегию (торгуем минимально возможным обьемом — 1 контракт или 1 акция). При восстановлении теоретической кривой капитала выше порога просадки — возобновляем работу полным обьемом. Порог просадки задается исходя из прошлых данных бэктеста, либо на глаз. Сильно зажимать порог нельзя. На глаз у меня получилось, что максимальная просадка стратегии с учетом процента капитала выделяемого на стратегию примерно равняется 3% на весь капитал. То есть, если стратегия торгует на 30% капитала, то пороговое значение должно быть примерно 10%. Здесь возможны исключения, например для стратегий с малой просадкой можно задавать пороговое значение чуть больше максимальной исторической просадки.
Мои тесты показывают, что при применении варианта 4 общая прибыль незначительно снижается, но так же снижается и просадка. Соотношение профит-просадка увеличивается примерно на 20%, для некоторых стратегий соотношение увеличивается в два раза.
Апдейт
Для примера equity-trading я рассмотрю трендовую стратегию на сбербанк.
Входные условия — только шорт, 100 контрактов фиксированный лот, без пирамидинга. С лонгом все понятно, последние пару лет стратегия зарабатывает без значительных просадок.
Эквити с фиксированным лотом, 100 контратктов.
Что то велосипедно-похожее иногда происходит и в нашем «опционном» мире. Я собираюсь сейчас прокомментировать несколько опционных
мнений-фокусов, вполне безобидных в текущей ситуации, но опасных при наступлении катастрофически-волатильных событий по типу «чучхэ понад усе».
Предварительные условия — обсуждается исключительно опционный рынок forts, ставки ноль.
Фокус первый.
Бытует мнение: распределение цен БА на момент экспирации, порождаемое ценами опционов, предполагает одинаковые вероятности смещения цен БА вверх или вниз.
Источник: интернеты, комментарии в них, и, увы((, Стас Бржозовский тут: https://smart-lab.ru/blog/411878.php
Факт: это полная ерунда. На самом деле, если допустить справедливость формулы Блэка для опционных цен (при условии постоянной волатильности на всех страйках), мы получим, что вероятность снижения цен на момент экспирации всегда выше, чем вероятность их роста.
Доказательство: берем и считаем в лоб. Например, при волатильности 50 и сроке до экспирации 1 год, вероятность снижения цены на момент экспирации составит 0,6. При волатильности 200, допустимой при катастрофах, ситуация будет еще интереснее. Правда в том, что матожидание распределения, порождаемого ценами опционов, совпадает с ценой БА в каждый момент. Но мало кто замечает подмену понятий и задумывается об этом.
Фокус второй.
Бытует мнение: дельта опциона колл на центральном страйке по модулю обязана совпадать с дельтой опциона пут и равняться 0,5.
Источник: многочисленные русскоязычные сайты, отдельные персонажи Смартлаба, тупые переводчики с английского на русский язык.
Факт — это вранье. Многие «канонические» авторы (Конноли, Натенберг, Мак-Миллан) действительно пишут, что дельта центрального колла ПРИМЕРНО совпадает по модулю с дельтой пута. И это правда, при низкой волатильности и малом времени до экспирации. Однако, при росте любого из этих двух показателей ситуация меняется кардинально.
Доказательство: все очень просто. Дельта центрального опциона колл (модель БШ) равна N(d1), d1>0, следовательно дельта центрального опциона колл в мире БШ всегда больше 0,5 и возрастает как с ростом iv, так и с ростом времени до экспирации. В предельном случае при бесконечной волатильности и/или времени до экспирации дельта центрального опциона колл — единица. Где живут риски неправильной оценки дельты? Сегодня — в Тихом океане. И если неистовый Ким попробует бабахнуть по душке-Дональду, то дельты опционов центральных страйков удивят многих. Пример: дельта центрального опцина колл при волатильности 50 и сроке до экспирации 1 год составляет 0,6. Каждый может в этом убедиться при помощи любого опционного калькулятора, живущего в интернетах.
Фокус третий.
Бытует мнение: вероятность выхода в деньги опциона колл совпадает с его дельтой.
Источник: интернеты и прочие сомнительные места.
Факт — это вранье дважды.
Доказательство: см первые два фокуса. Пример: вероятность выхода центрального опциона колл «в деньги» при сроке до экспирации 1 год и влатильности 50 составляет 0,4. Дельта 0,6.
Можно еще, наверное, пофокусничать с общепринятыми мнениями, но пора откланяться
PS
/М.А. Булгаков/:
«А может быть, не было никаких этих слов, а были другие на эту же музыку, какие-то неприличные крайне. Важно не это, а важно то, что в Варьете после всего этого началось что-то вроде столпотворения вавилонского.»
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