Блог им. kurd |Алготрейдинг. Очередные чудеса и их разоблачение

Новое чудо объявлено не так давно для растущих бумаг
smart-lab.ru/blog/1121015.php
и затем даже для не очень растущих
smart-lab.ru/blog/1124855.php

Как всегда у таких чудодеев, описание алгоритма неполно и неоднозначно.
На картинке автора чуда цена продажи на Close белой свечи всегда выше покупки первой из предыдущих чёрных свеч. В реальности это не гарантировано.
Поэтому уточним. Чтобы исполнить указание из первого описания стратегии
Ha зaкpытии бeлoй cвeчи зaкpывaeм paнee oткpытыe лoнги в плюc.
т.е. чтобы закрыть в плюс ВСЕ лонги, надо закрывать позицию не на первой попавшейся белой свече, а только по цене выше самой дорогой из предыдущих покупок.
Однако, тестирование показало, что гораздо больший выигрыш будет именно при закрытии позиции на первой белой свече!
При этом не все ранее открытые лонги закрываются в плюс.

Вот так выглядит страгегия  BlackAndWhite в программе WealthLab
for (int bar = 1; bar < Bars.Count; ++bar) {
  if (IsLastPositionActive && (bar == Bars.Count-1 ||
      Close[bar] > Open[bar])) {
    while (ActivePositions.Count > 0)
      ExitAtClose (bar, ActivePositions[0]);
  } else if (bar < Bars.Count-10 && Close[bar] < Open[bar]) {
    BuyAtClose (bar);
  }
}
История торгов Сбера с 01.01.2018 по 31.12.2024 на дневках добыта с сайта

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

Блог им. kurd |Алготрейдинг. Импорто-замещение своими руками


До недавнего времени я испытывал торговые стратегии в программе WealthLab. Но на днях возникла потребность проверки её результатов. Поэтому состряпал частичный аналог на C++.
Проверка показала значительное превосходство самоделки по быстродействию и полное совпадение результатов с фирменной системой — до копейки.

Вот как выглядит скрипт на C# в WealthLab
for (int bar = 1; bar != Bars.Count; ++bar) {
  if (IsLastPositionActive && (bar == Bars.Count-1 ||
      Close[bar] > Open[bar])) {
    while (ActivePositions.Count > 0)
      ExitAtClose (bar, ActivePositions[0]);
  } else if (bar < Bars.Count-10 && Close[bar] < Open[bar])
    BuyAtClose (bar);
}
и его аналог на C++
for (unsigned bar = 1; bar != Count; ++bar) {
  if (IsLastPositionActive() && (bar == Count-1 ||
      Close[bar] > Open[bar])) {
    while (ActivePositions.size() > 0)
      ExitAtClose (bar, ActivePositions.front());
  } else if (bar < Count-10 && Close[bar] < Open[bar])
    BuyAtClose (bar);
}
На всё-про-всё ушла рабочая неделя — годы уже не те.

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

Блог им. kurd |Алготрейдинг. Как искать оптимум параметров торговой системы

Не важно, какую функцию и как оптимизировать, минимум отклонения прогноза цены от фактической или максимум счёта (вложение+выигрыш), — возможны два подхода: 1) прямой перебор (brute force) всех вариантов и 2) градиентный метод (наискорейшего спуска).
Прямой перебор может потребовать громадных вычислений, не реализуемых практически.
Градиентный метод очень зависит от выбора начальной точки поиска. При множестве локальных экстремумов и только одном глобальном, существенно отличающемся от локальных, очень велика вероятность попадания на незначительный локальный экстремум. Метод деформируемого многогранника Нелдера-Мида (Simplex), хоть и решает некоторые трудности градиентного, в принципе от него не отличается.

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

Факт множественности экстремумов целевой функции можно считать вполне установленным.

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

Блог им. kurd |Алготрейдинг. Скрипт Lua для выгрузки истории котировок из Quik'а

Сайт finam.ru и mfd.ru перестали быть полезными для выгрузки истории котировок.
Это скрипт
-- График должен быть открыт в Quik'е
Class = "SPBFUT" -- "CETS_MTL" "CETS"
SecId="BRK4" -- "NGJ4" "GLDRUB_TOM" "USD000UTSTOM" "SiZ3"
Intrvl = INTERVAL_H1 -- D1 -- M5
Header = "<TICKER>;<PER>;<DATE>;<TIME>;"..
  "<OPEN>;<HIGH>;<LOW>;<CLOSE>;<VOL>"
Period = "60" -- Дневки - 0, W1, MN1, H4, H2 - недопустимо

function Log (i)
  local t = DS:T(i)
  local ymd = string.format ("%04d%02d%02d", t.year, t.month, t.day)
  local hms = string.format ("%02d%02d%02d", t.hour, t.min, t.sec);
  if not (IniDt <= ymd and ymd <= FinDt) or
     not (IniTm <= hms and hms <= FinTm) then return end
  local str = string.format ("%s;%s;%s;%s;%.4f;%.4f;%.4f;%.4f;%.0f\n"
    ,SecId, Period, ymd, hms
    ,DS:O(i), DS:H(i), DS:L(i), DS:C(i), DS:V(i))
  F:write (str)
end -- Log()

function OnInit (scriptPath)
  qu = require ("QuikUtil(qu)") -- lu,qc,tu
  ScriptDir, ScriptName = lu.


( Читать дальше )
  • обсудить на форуме:
  • Quik Lua

Блог им. kurd |Какие данные грузить в индикаторы для интрадея. Эврика!


Интрадей — игра внутри дня. Утром открыл позицию, в конце дневной сессии закрыл.
Что меня всегда заедало — утренние гэпы между разными датами. Например, всякие скользящие на них выходят из себя и не сразу входят в режим, пригодный для использования.

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

Проще всего не показывать индикатору эти гэпы и играть внутри дня только по внутридневным закономерностям.
В Quik'e это можно сделать, поставив «Фильтр по времени» в окне «Редактирование настроек графика» на интервал от 10:15 (чтобы исключить после-гэпие) до 18:45 и написав Lua-скрипт, который исправляет котировки, сокращая утренние гэпы на менее резкие изменения, например, на основе индикатра ATR за предыдущий день. И уже по этому графику ловить очищенные от гэпов внутридневные закономерности.

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

Блог им. kurd |Алготрейдинг. Об относительных приращениях

По мотивам напечатанного «Алготрейдинг. Как правильно склеивать фьючерсы»
smart-lab.ru/blog/1071687.php
Там, помимо прочего, упомянуто, что для обучения торговой системы лучше представлять историю котировок не абсолютными приращениями, а относительными.
Ну хотя бы для того, чтобы торговая система реагировала одинаково на изменение цены в 1%, независимо от текущего уровня в 1000 или в 2000 пунктов. Смысл не в доходе, а в доходности.
И предложены два варианта представления относительных приращений.
1) X[i]/X[i-1] — 1 и
2) ln (X[i]/X[i-1])

При отклонениях X[i] от X[i-1] в плюс или минус не более 10% различие этих вариантов в пределах 1%.
Алготрейдинг. Об относительных приращениях
Но при более значительных отклонениях X логарифмическое представление существенно меньше линейного.
Насколько оправдано логарифмическое преуменьшение?

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

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

Блог им. kurd |Алготрейдинг. Как правильно склеивать фьючерсы и зачем


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

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

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

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

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

Блог им. kurd |Алготрейдинг с обезличенными сделками. С чего начать

Обезличенные сделки в Quik'е содержат информацию о направлении сделок — Buy и Sell. Теоретически, это даёт дополнительные возможности прогноза движения цены. На практике дело сразу упирается в громадный объём этих тиковых данных и недоступность их во всех широко известных источниках.
Запрос «smart-lab Обезличенные сделки» в Яндексе даёт подборку
smart-lab.ru/blog/583818.php?ysclid=l5rmqam0or156053926
smart-lab.ru/tag/%D0%BE%D0%B1%D0%B5%D0%B7%D0%BB%D0%B8%D1%87%D0%B5%D0%BD%D0%BD%D1%8B%D0%B5%20%D1%81%D0%B4%D0%B5%D0%BB%D0%BA%D0%B8/?ysclid=l5rmr8efkg459101185
Разговоры сводятся к откачивание данных из Quik'а с помощью QLua и манипуляциям в Excel. Подход беспомощный и бесперспективный.

Во-первых, держать Quik включённым целый день только для получения данных по обезличенным сделкам впрок, для дальнейшего анализа — испытание терпения, немногим по силам. Ведь для реалистичности тестирования нужны данные за много дней.
Во-вторых,  объёмы данных за один торговый день — сотни тысяч записей, до полутора миллиона и более. Никакой Excel или Python не справятся. Выход в использовании источника с готовыми данными и эффективного средства программирования вроде C++, C# или Java.

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

Блог им. kurd |"Акела промахнулся" или "Мальчик Buybuy" слишком гениален, чтобы кто-то его мог понять?

По следам статей
«Рынок — это просто! Часть 3» 03 июня 2022, 01:12 «ВПК России — лучший»
smart-lab.ru/blog/808353.php
«грааль от BuyBuy» 05 июня 2022, 05:17 «Sergey Pavlov»
smart-lab.ru/blog/808971.php

Резюмируем сжато:
Цена актива в момент t — это x(t), приращение цены — d(t)=x(t)-x(t-1).
Индикатор id(t)=A*d(t-1)+B*d(t-2)
Покупка, когда id(t)>=0, продажа, когда id(t)<0.

Чтобы индикатор работал идеально на 2-х предыдущих барах, д.б.
d(t-1)=A*d(t-2)+B*d(t-3)
d(t-2)=A*d(t-3)+B*d(t-4)

Решение с точностью до множителя существует всегда:
A=d(t-1)*d(t-4)-d(t-2)*d(t-3)
B=d(t-2)*d(t-2)-d(t-1)*d(t-3)

Все это работает на таймфрейме 1 min и ниже.

И добавим однозначности:
Если считать, что d(t) = d(t-0) = x(t-0) — x(t-1),
то d(t-1) = x(t-1) — x(t-2) и т.д.

Скрипт C# на WealthLab
protected override void Execute()	{
    var d1 = (Close >> 1) - (Close >> 2);
    var d2 = (Close >> 2) - (Close >> 3);
    var d3 = (Close >> 3) - (Close >> 4);
    var d4 = (Close >> 4) - (Close >> 5);
    for (int i = 5; i < Bars.Count-2; i++) {
      double A = d1[i]*d4[i] - d2[i]*d3[i];
      double B = d2[i]*d2[i] - d1[i]*d3[i];
      double id = A*d1[i] + B*d2[i];
      int posDir = (! IsLastPositionActive) ? 0
        : LastPosition.PositionType == PositionType.Long ? 1 : -1;  
      if (id >= 0 && posDir != 1) {
        if (posDir == -1)
          ExitAtClose (i, LastPosition);
        BuyAtClose (i);
      } else if (id < 0 && posDir != -1) {
        if (posDir == 1)
          ExitAtClose (i, LastPosition);
        ShortAtClose (i);
      }
    } // for (int i
  } // Execute()
даёт результаты на минутках на 68 днях от 10:00 до 18:44 для сделок без комиссии и проскальзывания

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

Блог им. kurd |История доходности вложений в биржу с 1995

За начало взял сентябрь 1995, т.к. для индекса РТС Финам не даёт более ранних дат. Но для долгосрочника этот индекс — отстой. Так что его смотреть не будем.
Для сравнения принята цена Close на 31.01.2022.
Начнём с недельных графиков SnP500. Правда, его Финам выдал только с февраля 2001.
На верхнем графике для каждой недели подсчитаны доходности покупки по Open в процентах относительно Close последнего бара. Для последних 365 дней доходность не считается. Последний год на жёлтом фоне. Средняя доходность без поледнего года показана красной горизонталью. На нижнем графике синяя горизонталь показывает Close последнего бара.
История доходности вложений в биржу с 1995
Таблица построена за тот же период.
StrategyName Growth
SANDP-500_010216_220131dayly Weekly
ini     1326.6100
fin     4546.5400
growth     3.4272
bars         1091
years     20.9699
year%      6.0498
mean%     12.3421
nn;HiIdx;HiMax     ; HiDate    ; LoIdx;LoMin     ; LoDate    ;Days ;Drawdown ;Pct>=20
 0;    0;   1326.61; 17.02.2001;    86;    768.63; 11.10.2002;  601;   557.98;  42.06
 1;  344;   1576.03; 13.10.2007;   417;    667.04; 07.03.2009;  511;   908.99;  57.68
 2;  530;   1370.58; 06.05.2011;   552;   1075.09; 07.10.2011;  154;   295.49;  21.56
 3;  915;   2940.91; 21.09.2018;   929;   2346.58; 28.12.2018;   98;   594.33;  20.21
 4;  989;   3393.52; 21.02.2020;   994;   2192.07; 27.03.2020;   35;  1201.45;  35.40
Самая долгая просадка
 0;    0;   1326.61; 17.02.2001;    86;    768.63; 11.10.2002;  601;   557.98;  42.06
Наибольшая абсолютная
 4;  989;   3393.52; 21.02.2020;   994;   2192.07; 27.03.2020;   35;  1201.45;  35.40
Наибольшая относительная
 1;  344;   1576.03; 13.10.2007;   417;    667.04; 07.03.2009;  511;   908.99;  57.68
Результаты по NASDAQ

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

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