Торговля на форекс и ее базовая математика
Введение
Я являюсь разработчиком автоматических стратегий с опытом разработки более 5 лет и другого дополнительного софта. В данной статье я попытаюсь приоткрыть завесу тайны тем, кто еще только начинает торговать на форексе, либо на любой другой бирже, а также постараюсь ответить читателю на наиболее волнующие вопросы, которые начинает себе задавать любой трейдер, если он все-таки решил попытать удачу в данной области.
Я надеюсь, что эта статья будет полезной всем, и не только новичкам. Также не претендую на истину в последней инстанции, а лишь буду излагать реальную историю и реальные последствия своих исследований.
Некоторые из роботов и индикаторов написанных мной, есть у меня в продуктах. Но это лишь малая часть. Я писал самых различных роботов по самым разнообразным стратегиям. Я постараюсь показать, как данный подход при должном упорстве позволяет понять истинную природу рынка и на какие стратегии стоит обращать внимания, а на какие нет.
Почему так непонятно — где входить и где выходить?
Где входить и где выходить — это два важнейших вопроса, зная ответ на которые вам уже больше ничего не нужно будет знать. Но на них никогда нет простого ответа! На первый взгляд всегда можно выделить закономерность и следовать ей какое-то время, а как ее выделить, не имея специальных хитрых инструментов и индикаторов? Такими самыми простыми закономерностями, которые появляются всегда, являются ТРЕНД и ФЛЕТ. Тренд — это затяжное движение в какую-либо сторону, А Флет это более частые развороты.
Люди увидели их сразу, потому что человеческий глаз легко все это определяет даже без индикаторов. Но проблема состоит в том что, когда какая-то модель отработала, только тогда ее видно, но ведь она уже отработала и нет никакой гарантии, что это вообще какая-то модель, и тем более, что она будет и дальше развиваться. Иными словами, увидев какую-то закономерность, нет никаких гарантий, что на следующей свече рынок не долбанет в сторону, противоположную выбранной, и не сольет весь твой депозит. И так может произойти практически с любой стратегией, в которой вы наивно уверены на все 100 процентов. А почему так происходит, я постараюсь объяснить языком математики ниже.
Рыночные механизмы и уровни
Немного расскажу про ценообразование и вообще за счет чего движется цена. В рынке есть 2 силы. Рыночная и Лимитная. Так же, как есть 2 типа ордеров — рыночные и лимитные. Лимитные покупатели и продавцы заполняют стакан, а рыночные его разбирают. Стакан — это просто вертикальная шкала с ценами, на которых кто-то что-то хочет купить, а кто-то что-то хочет продать. Между лимитными продавцами и покупателями всегда есть промежуток, называемый спредом. Спред — это расстояние между лучшей ценой на покупку и лучшей ценой на продажу, измеренное в количестве минимальных движений цены. Покупатели хотят купить дешевле, а продавцы продать дороже. Поэтому лимитные ордера покупателей всегда внизу, а продавцов всегда вверху. Рыночные покупатели и продавцы заходят в стакан и происходит связывание двух ордеров — лимитного и рыночного, а когда лимитный ордер уничтожается, тогда происходит движение рынка.
Когда в рынке появляется открытый рыночный ордер, в большинстве случаев у него имеется Stop Loss и Take Profit. Точно так же, как и лимитные ордера, эти стопы размазаны по всему рынку и представляют собой в итоге уровни ускорения либо разворота цены. Все зависит от количества и вида стопов, ну и еще от обьема сделок. Зная эти уровни, можно знать, где и насколько цена выстрелит или отрeкошетит.
Лимитные же ордера тоже способны образовывать флуктуации и скопления? которые достаточно тяжело преодолеть. Чаще всего они возникают на важных ценовых точках, типа открытие дня или открытие недели. Когда торгуют от уровней, чаще всего подразумевают именно торговлю от уровней лимитных ордеров. Визуально попытаюсь кратко изобразить сказанное ниже.
Математическое описание рынка
То что мы видим в окне MetaTrader, это дискретная функция аргумента t, где t — время. Именно дискретная, т.к тиков конечное число, тики в нашем случае — это точки между, которыми нет абсолютно ничего. Тики это наиболее мелкий элемент возможной дискретизации цены, а бары или свечи M1 уже более крупный и т.д. M5, M15 .... В рынке есть случайная составляющая и есть закономерности. Закономерности бывают разных масштабов, разной длительности. Но по большей части рынок — это вероятностная пена, хаотичная, практически непредсказуемая. Чтобы понять рынок, лучше рассматривать его сквозь понятия теории вероятности. А дискретизация как раз нужна для того, чтобы можно было ввести понятие вероятности, плотности вероятности.
Для того чтобы ввести понятие матожидания, сначала нужно ввести понятие события и полной группы событий:
- Cобытие C1 — Профит, его величина равна tp
- Событие C2 — Убыток, его величина равна sl
- P1 — вероятность события C1
- P2 — вероятность события C2
События С1 и С2 образуют полную группу несовместных событий (т.е. какое-то из этих событий произойдет в любом случае), а следовательно, сумма этих вероятностей будет равна единице P2(tp,sl) + P2(tp,sl) = 1. Эта формула может пригодиться.
Тестируя советник или ручную стратегию со случайным открытием и используя StopLoss и TakeProfit, выбранные совершенно случайно, тем не менее получим всегда один неслучайный результат, получим матожидание равное "-(Spread)", что означало бы "0", если бы спред можно было выставить нулевым. Что приводит нас к выводу, что как не ставь стопы, на случайном рынке получим нулевое матожидание. А на не случайном прибыль или убыток при условии появления связанных с этим закономерностей. Та же к данным выводам можно прийти, положив что матожидание (Tick[0].Bid - Tick[1].Bid) так же равно нулю. Это довольно простые выводы, к которым можно прийти многими способами.
- M=P1*tp-P2*sl= P1*tp-(1- P1)*sl — для любого рынка
- P1*tp-P2*sl= 0 — для хаотичного рынка
Это основная формула хаотичного рынка, описывающая матожидание хаотичного закрытия и открытия ордеров, которые кроются по стопам. Решив последнее уравнение, получим все вероятности, которые нас интересуют, и для случая полной хаотичности и для случая обратного, при условии, что нам известны величины стопов.
Здесь лишь формула для простейшего случая, которую можно обобщить на случай любой стратегии, чем мы сейчас и займемся для того, чтобы добиться полного понимания из чего складывается конечное матожидание, которое в итоге нам и нужно сделать ненулевым. А также введем понятие профит фактора и напишем соответствующие формулы.
Теперь предположим, что наша стратегия предполагает закрытие не только по стопам, но и по каким-то сигналам. Для этого введем новое пространство событий С3, С4, в котором первое событие — это закрытие по стопам, а второе — по сигналам. Они также образуют полную группу несовместных событий и мы можем написать по аналогии :
M=P3*M3+P4*M4=P3*M3+(1-P3)*M4, где M3=P1*tp-(1- P1)*sl, a M4=Сумма(P0[i]*pr[i]) - Сумма(P01[j]*ls[j]); Сумма( P0[i] )+ Сумма( P01[j] ) =1
- M3 — мат.ожидание величины профита при закрытии стоп приказом.
- M4 — мат.ожидание величины профита при закрытии по сигналу.
- P1 , P2 — вероятности срабатывания стопов при условии что какой то из стопов в любом случае сработает.
- P0[i] — вероятность закрытия сделки с pr[i] профитом при условии что сделка не задела стопы. i — номер варианта закрытия
- P01[j] — вероятность закрытия сделки с ls[j] убытком при условии что сделка не задела стопы. j — номер варианта закрытия
Т. е. у нас есть 2 несовместных события, из исходов которых составлены еще 2 независимых пространства событий, в которых мы также выделяем полную группу. Только теперь вероятности P1, P2, P0[i], P01[j] — это условные вероятности. А P3, P4 — это вероятности гипотез. Условная вероятность — это вероятность наступления какого-либо события при условии, что произошла гипотеза. Все в строгом соответствии с формулой полной вероятности (формула Бейеса). Если кто не знаком, советую почитать и хорошенько изучить. При этом так же для совершенно бестолковой и хаотичной торговли M=0.
Вот теперь наша формула стала гораздо понятнее и шире, теперь мы учитываем и закрытие по стопам, и закрытие по сигналам. Но мы можем пойти дальше, следуя этой аналогии, и написать общую формулу для любой стратегии, которая учитывает даже динамические стопы. Этим и займемся. Введем еще N событий, образующих полную группу, которые означают открытие сделок, открытых с одинаковыми StopLoss и TakeProfit. CS[1] .. CS[2] .. CS[3] ....... CS[N] . При этом точно также PS[1] + PS[2] + PS[3] + ....... +PS[N] = 1.
M = PS[1]*MS[1]+PS[2]*MS[2]+ ... + PS[k]*MS[k] ... +PS[N]*MS[N] , MS[k] = P3[k]*M3[k]+(1- P3[k])*M4[k], M3[k] = P1[k] *tp[k] -(1- P1[k] )*sl[k], M4[k] = Сумма(i)(P0[i][k]*pr[i][k]) - Сумма(j)(P01[j][k] *ls[j][k] ); Сумма(i)( P0[i][k] )+ Сумма(j)( P01[j][k] ) =1.
- PS[k] — вероятность выставления k - го варианта стопов.
- MS[k] — мат.ожидание закрытых сделок с k - ми стопами.
- M3[k] — мат.ожидание величины профита при закрытии стоп приказом с k - ми стопами.
- M4[k] — мат.ожидание величины профита при закрытии по сигналу с k - ми стопами.
- P1[k] , P2[k] — вероятности срабатывания стопов при условии что какой то из стопов в любом случае сработает.
- P0[i][k] — вероятность закрытия сделки с pr[i][k] прибылью , по сигналу с k - ми стопами. i — номер варианта закрытия
- P01[j][k] — вероятность закрытия сделки с ls[j][k] убытком , по сигналу с k - ми стопами. j — номер варианта закрытия
Точно так же, как и в прошлых более простых формулах, M=0 при бестолковой торговле и отсутствии спреда. Максимум, что вы можете сделать — это изменить саму стратегию, но если в стратегии нет рационального зерна, то вы просто измените баланс всех этих переменных, но все равно получите "0". А чтобы внести в это равновесие дисбаланс, необходимо знать главное — вероятность движения рынка в каком-либо направлении в какой-либо фиксированный отрезок движения цены в пунктах, либо матожидание движения цены в фиксированный отрезок времени. Точки входа и точки выхода выбираются именно из этого соображения. Найдете такие, значит будет у вас прибыльная стратегия.
Теперь создадим формулу для профит фактора. PF = Profit/Loss. По определению профитфактор — это отношение прибыли к убытку. Если число больше 1, то стратегия прибыльная, если нет, то убыточная. Это можно переопределить, используя матожидание. PrF=Mp/Ml. Что означает отношение матожидания чистой прибыли к матожиданию чистого убытка. Напишем их формулы.
- Mp = PS[1]*MSp[1]+PS[2]*MSp[2]+ ... + PS[k]*MSp[k] ... +PS[N]*MSp[N] , MSp[k] = P3[k]*M3p[k]+(1- P3[k])*M4p[k] , M3p[k] = P1[k] *tp[k], M4p[k] = Сумма(i)(P0[i][k]*pr[i][k])
- Ml = PS[1]*MSl[1]+PS[2]*MSl[2]+ ... + PS[k]*MSl[k] ... +PS[N]*MSl[N] , MSl[k] = P3[k]*M3l[k]+(1- P3[k])*M4l[k] , M3l[k] = (1- P1[k] )*sl[k], M4l[k] = Сумма(j)(P01[j][k]*ls[j][k])
Сумма(i)( P0[i][k] ) + Сумма(j)( P01[j][k] ) =1.
- MSp[k] — матожидание закрытых сделок с k - ми стопами.
- MSl[k] — матожидание закрытых сделок с k - ми стопами.
- M3p[k] — матожидание величины профита при закрытии стоп приказом с k - ми стопами.
- M4p[k] — матожидание величины профита при закрытии по сигналу с k - ми стопами.
- M3l[k] — матожидание величины убытка при закрытии стоп приказом с k - ми стопами.
- M4l[k] — матожидание величины убытка при закрытии по сигналу с k - ми стопами.
Для более глубокого понимания схематично изображу все вложенности событий:
По сути, те же самые формулы, только в первой вырезаны члены, относящиеся к убытку, а во второй к прибыли. При бестолковой торговле PrF = 1. Опять же при условии нулевого спреда. M, PrF — две величины, которых вполне достаточно для того, чтобы оценить стратегию со всех сторон.
Присутствует возможность оценить трендовость или флетовость того или иного инструмента с помощью той же самой теории вероятностей и комбинаторики, ну или увидеть некоторые отличия от от хаотичности с помощью плотностей распределения вероятностей.
Будем строить график плотности вероятности распределения случайной величины для дискретизированной цены по фиксированному шагу H в пунктах. Будем считать, что если цена прошла H в любом направлении, то произошел шаг. В качестве случайной величины по оси X будем откладывать вертикальное движение графика по оси цены измеренное в количестве шагов. При этом обязательно, чтобы произошло n шагов, только тогда мы можем оценить общее движение цены.
- n — общее количество шагов, оно всегда постоянно
- d — количество шагов на падение цены
- u — количество шагов на возрастание цены
- s — итоговое движение вверх в шагах
Определив эти величины вычислим u и d:
Для того чтобы обеспечить итоговое "s" шагов вверх (при этом величина может быть отрицательной, что означает шаги вниз ), нужно обеспечить некоторое количество шагов вверх и вниз: "u", "d". При этом итоговое перемещение вверх или вниз "s" будет зависеть от всех шагов в целом:
n=u+d;
s=u-d;
Это система 2 уравнений, решив которую можно получить u и d:
u=(s+n)/2, d=n-u.
При этом не все значения "s" подходят для определенного значения "n". Шаг между возможными значениями s всегда равен 2. Это нужно для того, чтобы обеспечить "u" и "d" натуральными значениями, так как мы будем их использовать для комбинаторики, а точнее, для вычисления сочетаний. Если эти числа дробные, тогда мы не можем вычислить факториал. А факториал — это краеугольный камень всей комбинаторики. Ниже приведено схематичное изображение всех возможных вариантов развития сценария для 18 шагов. Оно должно помочь визуально понять, насколько обширны варианты событий.
Несложно посчитать, что для всего многообразия вариантов ценообразования, таких вариантов будет 2^n, так как после каждого шага есть всего 2 варианта движения, вверх или вниз. Не нужно пытаться осознать каждый из этих вариантов, это невозможно. Нужно лишь знать что у нас есть n уникальных ячеек, из которых u и d, должно быть вверх и вниз соответственно. При этом те варианты, где имеются одинаковые числа u и d в итоге дают одинаковое s. Чтобы посчитать общее количество вариантов которое дадут одно и то же "s" мы можем использовать формулу сочетания из комбинаторики С=n!/(u!*(n-u)!), а также эквивалентную ей формулу С=n!/(d!*(n-d)!). При различных u,d мы получаем одно и то же значение C. Так как сочетания можно составить как по возрастающим сегментам так и по падающим, непременно возникает дежавю и вопрос — а по каким сегментам составлять сочетания? Ответ: по любым. Так как эти сочетания эквивалентны, несмотря на свои различия, что я докажу ниже, используя программку на основе MathCad 15.
Теперь, когда мы определили количество сочетаний для каждого варианта развития событий, то мы можем определить вероятность того или иного сочетания (либо события, кому как угодно). P = С/(2^n). Данную величину можно посчитать для всех "s", и сумма этих вероятностей всегда будет равна 1, так как какой-то из этих вариантов в любом случае произойдет. На основе данного массива вероятностей можно построить график плотности вероятности относительно случайной величины "s", учитывая при этом, что шаг s равен 2. Тогда плотность на конкретном шаге можно получить просто делением вероятности на величину шага s, т. е. на 2. Все это из-за того, что мы не можем построить непрерывную функцию для дискретных величин. И данная плотность будет актуальна на полшага влево и право, то есть на 1. Оно обеспечит визуальное понимание, где находятся узлы, и обеспечит возможность численного интегрирования. Но еще нужно не забыть, что есть еще отрицательные "s", и для них мы просто зеркально отразим график относительно оси плотности вероятности. Для четных n нумерация узлов начинается с 0, для нечетных с 1. Так как при четных n мы не можем обеспечить нечетные s, а при нечетных n мы не можем обеспечить четные s. Для прояснения ситуации привожу скриншот программы расчета:
Здесь приведено все? что нужно для понимания. Данная программа будет приложена файлом к статье? и все желающие смогут поиграться с параметрами. При этом очень многих интересует, как определить — сейчас тренд или флет? Я придумал собственные формулы для количественной оценки трендовости инструмента, ну или флетовости соответственно. При этом тренд бывает разный, Alpha и Betta.Я разделил их на 2 группы, альфа — это тенденция либо на покупку, либо на продажу, бетта — это просто стремление продолжения движения без ярко выраженного движения в сторону покупки или продажи, а флет — это стремления вернуться к стартовой цене.
Вообще говоря, определение тренда и флета у многих разнится. Я же пытаюсь дать более жесткое определение всем этим явлениям. Ведь даже лишь от элементарного понимания этих вещей и того, как их количественно выразить, можно вдохнуть жизнь во множество стратегий, которые до этого считались мертвыми или вульгарными. Приведу эти основные формулы:
K=Integral(p*|x|)
или
K=Summ(P[i]*|s[i]|)
Первый вариант для непрерывной случайной величины, а второй для дискретной. В нашем случае мы для наглядности дискретную величину сделали непрерывной, соответственно, воспользовались первой формулой. Интеграл у нас от минус до плюс бесконечности. Это коэффициент равновесия или коэффициент тренда. Вычислив его для случайной величины, мы получим точку равновесия, относительно которой можем сравнивать реальное распределение котировки с эталонным. Если Кp > K, то рынок можно считать трендовым, и если Кp < K, то рынок флетовый.
При этом можно также вычислить максимальное значение этого коэффициента, он будет равен KMax=1*Max(|x|) или KMax=1*Max(|s[i]|). Также можно вычислить и минимальное значение данного коэффициента, оно будет равно KMin=1*Min(|x|) = 0 или KMin=1*Min(|s[i]|) = 0. Средняя точка KMid, минимум и максимум, все что нужно для того, чтобы оценить трендовость или флетовость анализируемого участка в процентах.
if ( K >= KMid ) KTrendPercent=((K-KMid)/(KMax-KMid))*100 else KFletPercent=((KMid-K)/KMid)*100.
Но этого еще недостаточно для того, чтобы полностью охарактеризовать ситуацию. Для этого нам на помощь приходит второй коэффициент T=Integral(p*x), T=Summ(P[i]*s[i]), который по сути отражает матожидание числа шагов вверх, но и одновременно является показателем альфа тренда. Если Tp > 0, то тренд на покупку, если Tp < 0, то на продажу, т. к. T=0 для случайного блуждания.
Найдем максимальное и минимальное значение этого коэффициента: TMax=1*Max(x) или TMax=1*Max(s[i]), а минимальный по модулю равен максимальному, но просто отрицательный TMin= - TMax. Если измерять процент альфа тренда от 100 до -100, то можно написать формулы для вычисления данной величины, аналогично предыдущей величине:
APercent=( T /TMax)*100.
Если процент положительный, то налицо восходящий тренд, если минус, то нисходящий. Вообще говоря, ситуации могут быть смешанные. Может быть и альфа флет и альфа тренд, а вот тренд и флет уже нет. Либо то, либо то. Ниже вы увидите графическую иллюстрацию сказанного и примеры построенных графиков плотностей для различного числа шагов.
Как видно, при увеличении числа шагов график становится уже и выше. Для каждого числа шагов соответствующие альфа и бетта значения будут различными как и сама картина распределения. При смене числа шагов эталонное распределение нужно пересчитывать.
Все эти формулы можно применять для построения автоматических торговых систем, можно также сделать индикаторы, основываясь на этих алгоритмах. У кого-то уже реализованы данные вещи в советниках. Одно можно сказать: лучше пользоваться этим анализом, чем не пользоваться. У человека, знакомого с математикой, уже сразу появятся идеи, как это применить. А те, кому это по каким-то причинам тяжеловато, не беда — читаем, разбираемся, пробуем. Все получится.
Пишем простой индикатор
В этой части статьи трансформируем наши простейшие математические изыскания в индикатор, который поможет нам с точками входа в рынок, а также послужит базой для написания советников. Будем писать наш индикатор на MQL5. Но я по-прежнему считаю старый добрый MT4 гораздо лучше своего потомка. Поэтому код будет максимально адаптирован под перенос на MQL4. Вообще, я пропогандирую и сам использую подход без лишних заморочек. К ООП прибегаю в самый последний момент, если вижу, что код становится излишне громоздким и нечитабельным. Но в 90% случаев удается этого избежать. Красивенькие панельки, кнопочки, куча информации на графике — как по мне попса чистой воды. Это только для конечного потребителя. Я же всегда стараюсь писать необходимый минимум. Как в математике: необходимо и достаточно.
Начнем с входных параметров индикатора.
input uint BarsI=990;//Bars TO Analyse ( start calc. & drawing ) input uint StepsMemoryI=2000;//Steps In Memory input uint StepsI=40;//Formula Steps input uint StepPoints=30;//Step Value input bool bDrawE=true;//Draw Steps
Когда индикатор загружается, мы можем провести стартовый расчет некоторого количества шагов, беря за основу некие последние свечки графика. Также нам понадобится буффер, который будет хранить информацию о наших последних шагах, и по мере их поступления удалять старые, а на их место записывать новые. У него тоже будет ограниченный размер. Этот же размер будем использовать для отрисовки шагов на графике. Мы должны Задать индикатору для какого количества шагов мы будем строить распределение и вычислять необходимые величины. Далее мы должны сказать системе, сколько в пунктах размер нашего шага. Ну и наконец, нужна ли нам визуализация этих шагов. Шаги будут визуализированы с помощью рисования на графике.
Вообще стиль индикатора я выбрал в отдельном окне, там будет нарисовано нейтральное распределение и текущая ситуация. Две линии, но я хотел еще одну линию на графике. К сожалению возможности индикаторов не предполагают рисование и в отдельном и основном окне, поэтому пришлось прибегнуть к рисованию.
Для того чтобы иметь возможность обращаться к данным баров, как в MQL4, я всегда прибегаю к небольшой хитрости:
//переменные для переноса в MQL5 double Close[]; double Open[]; double High[]; double Low[]; long Volume[]; datetime Time[]; double Bid; double Ask; double Point=_Point; int Bars=1000; MqlTick TickAlphaPsi; void DimensionAllMQL5Values()//задаем нужный размер массивов { ArrayResize(Close,BarsI,0); ArrayResize(Open,BarsI,0); ArrayResize(Time,BarsI,0); ArrayResize(High,BarsI,0); ArrayResize(Low,BarsI,0); ArrayResize(Volume,BarsI,0); } void CalcAllMQL5Values()//пересчитаем все массивы { ArraySetAsSeries(Close,false); ArraySetAsSeries(Open,false); ArraySetAsSeries(High,false); ArraySetAsSeries(Low,false); ArraySetAsSeries(Volume,false); ArraySetAsSeries(Time,false); if( Bars >= int(BarsI) ) { CopyClose(_Symbol,_Period,0,BarsI,Close); CopyOpen(_Symbol,_Period,0,BarsI,Open); CopyHigh(_Symbol,_Period,0,BarsI,High); CopyLow(_Symbol,_Period,0,BarsI,Low); CopyTickVolume(_Symbol,_Period,0,BarsI,Volume); CopyTime(_Symbol,_Period,0,BarsI,Time); } ArraySetAsSeries(Close,true); ArraySetAsSeries(Open,true); ArraySetAsSeries(High,true); ArraySetAsSeries(Low,true); ArraySetAsSeries(Volume,true); ArraySetAsSeries(Time,true); SymbolInfoTick(Symbol(),TickAlphaPsi); Bid=TickAlphaPsi.bid; Ask=TickAlphaPsi.ask; } ////////////////////////////////////////////////////////////
Теперь наш код максимально совместим с MQL4 и без особого труда и очень быстро можно из него сделать MQL4-аналог.
Продолжим. Для того чтобы описать шаги, нам сначала надо описать узлы.
struct Target//структура для хранения информации о узле { double Price0;//цена узла datetime Time0;//время узла bool Direction;//направление шага заканчивающегося в текущем узле bool bActive;//активен ли узел }; double StartTick;//цена стартового тика Target Targets[];//тики точек назначения ( точки отстоящие от предыдущей на StepPoints пунктов )
Дополнительно нам понадобится точка, от которой отсчитывать следующий шаг. Узел хранит информацию о себе и о шаге, который закончился на нем, а также есть булевая составляющая, которая говорит — активен ли узел. Только когда вся память массива узлов заполнится реальными узлами, тогда и начнет высчитываться реальное распределение, потому как реальное распределение высчитывается по шагам. Нет шагов — значит нет расчета.
Далее у нас должна иметься возможность обновлять состояние шагов на каждом тике, а также провести приближенный расчет по барам при инициализации индикатора.
bool UpdatePoints(double Price00,datetime Time00)//обновляет массив узлов и в случае нового узла возвращает true { if ( MathAbs(Price00-StartTick)/Point >= StepPoints )//если размер шага достиг требуемого то записываем его и сдвигаем массив назад { for(int i=ArraySize(Targets)-1;i>0;i--)//сначала сдвинем все назад { Targets[i]=Targets[i-1]; } //после сгенерируем новый узел Targets[0].bActive=true; Targets[0].Time0=Time00; Targets[0].Price0=Price00; Targets[0].Direction= Price00 > StartTick ? true : false; //и в конце переопределим стартовый тик для отслеживания следующего узла StartTick=Price00; return true; } else return false; } void StartCalculations()//приближенные стартовые вычисления (по ценам закрытия баров) { for(int j=int(BarsI)-2;j>0;j--) { UpdatePoints(Close[j],Time[j]); } }
Далее опишем методы и переменные необходимые для того, чтобы посчитать все параметры нейтральной линии. Ее ордината будет представлять собой вероятность конкретного сочетания или исхода, кому как угодно. Скажу сразу, я не люблю называть это нормальным распределением, потому как нормальное распределение величина непрерывная, а в данном случае мы строим график дискретной величины. Кроме того, нормальное распределение — это плотность вероятности, а не вероятность, как в случае нашего индикатора. Тут нам удобнее строить график вероятности, а не ее плотности.
int S[];//массив итоговых шагов вверх int U[];//массив шагов вверх int D[];//массив шагов вниз double P[];//массив вероятностей конкретного исхода double KBettaMid;//нейтральное значение Betta коэффициента double KBettaMax;//максимальное значение Betta коэффициента //минимальное Betta = 0 его нет смысла задавать double KAlphaMax;//максимальное значение Alpha коэффициента double KAlphaMin;//минимальное значение Alpha коэффициента //среднее Alpha = 0 его нет смысла задавать int CalcNumSteps(int Steps0)//посчитаем число шагов { if ( Steps0/2.0-MathFloor(Steps0/2.0) == 0 ) return int(Steps0/2.0); else return int((Steps0-1)/2.0); } void ReadyArrays(int Size0,int Steps0)//подготовим массивы { int Size=CalcNumSteps(Steps0); ArrayResize(S,Size); ArrayResize(U,Size); ArrayResize(D,Size); ArrayResize(P,Size); ArrayFill(S,0,ArraySize(S),0);//чистим ArrayFill(U,0,ArraySize(U),0); ArrayFill(D,0,ArraySize(D),0); ArrayFill(P,0,ArraySize(P),0.0); } void CalculateAllArrays(int Size0,int Steps0)//посчитаем все массивы { ReadyArrays(Size0,Steps0); double CT=CombTotal(Steps0);//количество комбинаций for(int i=0;i<ArraySize(S);i++) { S[i]=Steps0/2.0-MathFloor(Steps0/2.0) == 0 ? i*2 : i*2+1 ; U[i]=int((S[i]+Steps0)/2.0); D[i]=Steps0-U[i]; P[i]=C(Steps0,U[i])/CT; } } void CalculateBettaNeutral()//посчитаем все Alpha и Betta коэффициенты { KBettaMid=0.0; if ( S[0]==0 ) { for(int i=0;i<ArraySize(S);i++) { KBettaMid+=MathAbs(S[i])*P[i]; } for(int i=1;i<ArraySize(S);i++) { KBettaMid+=MathAbs(-S[i])*P[i]; } } else { for(int i=0;i<ArraySize(S);i++) { KBettaMid+=MathAbs(S[i])*P[i]; } for(int i=0;i<ArraySize(S);i++) { KBettaMid+=MathAbs(-S[i])*P[i]; } } KBettaMax=S[ArraySize(S)-1]; KAlphaMax=S[ArraySize(S)-1]; KAlphaMin=-KAlphaMax; } double Factorial(int n)//факториал числа n { double Rez=1.0; for(int i=1;i<=n;i++) { Rez*=double(i); } return Rez; } double C(int n,int k)//сочетания из n по к { return Factorial(n)/(Factorial(k)*Factorial(n-k)); } double CombTotal(int n)//всего комбинаций { return MathPow(2.0,n); }
Все эти функции необходимо вызывать в нужном месте. Все функции здесь предназначены либо для вычисления значений массивов, либо реализуют какие-то вспомогательные математические функции, кроме первых двух. Они вызываются при инициализации вместе с расчетом нейтрального распределения, и служат для задания размеров наших массивов.
Далее по аналогии создадим блок кода для расчета реального распределения и его основных параметров.
double AlphaPercent;//процент альфа тренда double BettaPercent;//процент бетта тренда int ActionsTotal;//всего уникальных случаев в Массиве шагов учитывая количество шагов для проверки варианта int Np[];//количество реальных исходов конкретной ситуации в плюс int Nm[];//количество реальных исходов конкретной ситуации в минус double Pp[];//вероятность конкретного шага в плюс double Pm[];//вероятность конкретного шага в минус int Sm[];//количество шагов в минус void ReadyMainArrays()//подготовим главные массивы { if ( S[0]==0 ) { ArrayResize(Np,ArraySize(S)); ArrayResize(Nm,ArraySize(S)-1); ArrayResize(Pp,ArraySize(S)); ArrayResize(Pm,ArraySize(S)-1); ArrayResize(Sm,ArraySize(S)-1); for(int i=0;i<ArraySize(Sm);i++) { Sm[i]=-S[i+1]; } ArrayFill(Np,0,ArraySize(Np),0);//чистим ArrayFill(Nm,0,ArraySize(Nm),0); ArrayFill(Pp,0,ArraySize(Pp),0); ArrayFill(Pm,0,ArraySize(Pm),0); } else { ArrayResize(Np,ArraySize(S)); ArrayResize(Nm,ArraySize(S)); ArrayResize(Pp,ArraySize(S)); ArrayResize(Pm,ArraySize(S)); ArrayResize(Sm,ArraySize(S)); for(int i=0;i<ArraySize(Sm);i++) { Sm[i]=-S[i]; } ArrayFill(Np,0,ArraySize(Np),0);//чистим ArrayFill(Nm,0,ArraySize(Nm),0); ArrayFill(Pp,0,ArraySize(Pp),0); ArrayFill(Pm,0,ArraySize(Pm),0); } } void CalculateActionsTotal(int Size0,int Steps0)//всего возможных исходов составленые из массива шагов { ActionsTotal=(Size0-1)-(Steps0-1); } bool CalculateMainArrays(int Steps0)//посчитаем основные массивы { int U0;//шагов вверх int D0;//шагов вниз int S0;//итоговое количество шагов вверх if ( Targets[ArraySize(Targets)-1].bActive ) { ArrayFill(Np,0,ArraySize(Np),0);//чистим ArrayFill(Nm,0,ArraySize(Nm),0); ArrayFill(Pp,0,ArraySize(Pp),0); ArrayFill(Pm,0,ArraySize(Pm),0); for(int i=1;i<=ActionsTotal;i++) { U0=0; D0=0; S0=0; for(int j=0;j<Steps0;j++) { if ( Targets[ArraySize(Targets)-1-i-j].Direction ) U0++; else D0++; } S0=U0-D0; for(int k=0;k<ArraySize(S);k++) { if ( S[k] == S0 ) { Np[k]++; break; } } for(int k=0;k<ArraySize(Sm);k++) { if ( Sm[k] == S0 ) { Nm[k]++; break; } } } for(int k=0;k<ArraySize(S);k++) { Pp[k]=Np[k]/double(ActionsTotal); } for(int k=0;k<ArraySize(Sm);k++) { Pm[k]=Nm[k]/double(ActionsTotal); } AlphaPercent=0.0; BettaPercent=0.0; for(int k=0;k<ArraySize(S);k++) { AlphaPercent+=S[k]*Pp[k]; BettaPercent+=MathAbs(S[k])*Pp[k]; } for(int k=0;k<ArraySize(Sm);k++) { AlphaPercent+=Sm[k]*Pm[k]; BettaPercent+=MathAbs(Sm[k])*Pm[k]; } AlphaPercent= (AlphaPercent/KAlphaMax)*100; BettaPercent= (BettaPercent-KBettaMid) >= 0.0 ? ((BettaPercent-KBettaMid)/(KBettaMax-KBettaMid))*100 : ((BettaPercent-KBettaMid)/KBettaMid)*100; Comment(StringFormat("Alpha = %.f %%\nBetta = %.f %%",AlphaPercent,BettaPercent));//выводим эти числа на экран return true; } else return false; }
Здесь все похоже, но массивов намного больше, так как график не всегда будет зеркален относительно вертикальной оси. Для этого нам понадобятся дополнительные массивы и переменные, но в целом логика проста: считаем количество исходов конкретного случая и потом делим на общее количество всех исходов. Так мы получим все вероятности (ординаты) и соответствующие им абсциссы. Я не буду углубляться и разжевывать каждый цикл, каждую переменную. Все эти сложности, по сути, для того чтобы не было потом проблем с переносом значений в буфферы без лишних выкрутасов. Тут все почти так же: определяем размер массивов, считаем их. Потом считаем процент альфа тренда и бетта тренда и выводим его в верхний левый угол экрана.
Осталось определить, что и где мы будем вызывать.
int OnInit() { //--- indicator buffers mapping SetIndexBuffer(0,NeutralBuffer,INDICATOR_DATA); SetIndexBuffer(1,CurrentBuffer,INDICATOR_DATA); CleanAll(); DimensionAllMQL5Values(); CalcAllMQL5Values(); StartTick=Close[BarsI-1]; ArrayResize(Targets,StepsMemoryI);//макс количество узлов CalculateAllArrays(StepsMemoryI,StepsI); CalculateBettaNeutral(); StartCalculations(); ReadyMainArrays(); CalculateActionsTotal(StepsMemoryI,StepsI); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[]) { CalcAllMQL5Values(); if ( UpdatePoints(Close[0],TimeCurrent()) ) { if ( CalculateMainArrays(StepsI) ) { if ( bDrawE ) RedrawAll(); } } int iterator=rates_total-(ArraySize(Sm)+ArraySize(S))-1; for(int i=0;i<ArraySize(Sm);i++) { iterator++; NeutralBuffer[iterator]=P[ArraySize(S)-1-i]; CurrentBuffer[iterator]=Pm[ArraySize(Sm)-1-i]; } for(int i=0;i<ArraySize(S);i++) { iterator++; NeutralBuffer[iterator]=P[i]; CurrentBuffer[iterator]=Pp[i]; } return(rates_total); }
В качестве буферов здесь используются CurrentBuffer,NeutralBuffer. Для простоты сделал отображение на ближайших свечках к рынку. Каждая вероятность на отдельном баре. Это позволило избавиться от лишних сложностей. Просто приближаете или отдаляете график и все видно. Функции CleanAll() и RedrawAll() не стал приводить. Вообще их можно закомментировать и все будет прекрасно работать только без отрисовки . Блок для отрисовки я не стал здесь приводить. Кому надо, посмотрят в исходнике. Ничего интересного там нет. Индикатор будет приложен к статье. Индикатор будет приложен в 2-х версиях — для MetaTrader 4 и для MetaTrader 5.
Выглядеть это все будет так.
Ну и вариант с другими входными параметрами и стилем окна.
Обзор наиболее интересных стратегий по моей версии
И сам делал советники, и видел чужие. По моему скромному опыту, что-то интересное получается, когда используют сетку или когда используют мартингейл, либо оба. Но, строго говоря, что у мартингейла, что у сетки — матожидание "0". Не обманывайтесь вверх идущими графиками, ибо получите в один прекрасный момент жирного лося. Проверять не советую. Поверьте на слово... Есть работающие сетки, и они продаются в маркете. Они неплохо работают и даже показывают профит фактор в районе 3-6. Это очень красивая цифра на самом деле, при том что работает все это на любой валютной паре. Но не так-то легко придумать фильтры, которые позволят тебе выиграть. С помощью метода, описанного выше, вы сможете как раз отфильтровать эти сигналы. Для сетки нужен тренд, а в какую сторону — не важно.
Мартингейл и сетка — это пример наиболее простых стратегий, которые у всех на виду, у всех на слуху. Все из-за их простоты и доступности. Но вот грамотно применить их может далеко не каждый. Следующими по сложности идут самоадаптирующиеся советники. Адаптироваться они могут к чему угодно, к флету, к тренду, любым другим закономерностям. Берется некий кусок рынка, на нем ищутся закономерности, а потом проторговываются некий небольшой промежуток времени в надежде на то, что закономерность останется еще какое то время.
Особую нишу занимают экзотические системы с загадочными, ни на что не похожими алгоритмами, абузящими как раз хаотичность рынка. Такие системы работают на чистой математике и способны приносить прибыль на любом инструменте. В любом временном отрезке. Эта прибыль не велика, но стабильна. Я как раз последнее время занимаюсь такими системами. Так же в эту нишу можно отнести роботов на основе брутфорса. Брутфорс можно выполнять на дополнительном софте. В следующей статье я покажу свой вариант такой программы.
Верхнюю нишу занимают роботы на основе нейросетей и похожего софта. Такие роботы могут показывать самые разные результаты. Сложность таких систем максимальна. Ведь нейросеть это прообраз ИИ. Правильно написав нейросеть и правильно обучив ее, можно добиться таких показателей прибыли, каких не сможет добиться никакая другая стратегия.
Что до арбитража, на мой взгляд, сейчас его возможности практически нулевые. Советники у меня есть. Толку от них "0".
Стоит ли вообще игра свеч?
Кто-то играет на бирже из-за азарта, кто-то ищет легких и быстрых денег, ком- то просто интересно изучать рынок, процессы в нем, строить формулы, теории. А у кого-то просто нет иного выбора из-за того, что нет пути назад. Я отношусь скорее к последней категории. При всех своих знаниях и опыте, на данный момент не имею прибыльного стабильного счета. Советники есть, тестер говорит дерзай... Но не все так просто ).
Для тех кто думает быстро озолотиться, скорее всего вы получите обратный сценарий. Ведь рынок не создан для того чтобы простой трейдер выигрывал. Он создан с обратной целью, и для тех кто этого еще не понял, самое время понять. Но если у вас железные яйца, и вы решили что вы сможете, запасайтесь вагоном времени и терпения. Быстрого результата вам не видать. А уж если вы не умеете программировать, писать советники, то у вас вообще шансов практически нет. Видел много всяких псевдо трейдеров которые утверждают что-то, проторговав 20-30 сделок. При этом я пишу советника, проверяю, ну год-два это работает, начинаю глубже в историю уходить, а там все наоборот... Это еще в лучшем случае.
А обычно там вообще ни черта не работает. Вообще так-то ручками можно неплохо торговать, но это скорее искусство, чем вы найдете какую-то простую и понятную систему. Вообще, вся информация об этом — это просто каша каких-то фактов, домыслов. Одно другому противоречит, что-то здравое, что-то нет. Попробуй разберись в этой каше... Паттерны, уровни, фибоначчи, свечные модели, прочий бред ... Заработать на рынке можно, но времени вы потратите очень много. Лично я считаю, что оно того не стоит. Лучше бы я пошел программистом работать, сейчас бы уже где-нибудь коктейль попивал и в ус не дул. Да и с точки зрения математики, рынок это просто кривулька — неинтересная двумерная. Не хотел бы я всю жизнь смотреть на эти унылые свечки ).
Возможен ли грааль и где его искать?
Если уж мы все-таки дошли до этого вопроса, скажу сразу — Грааль более чем возможен. И у меня есть советники, которые это доказывают. Хотя эти советники не такие уж и сложные, да и матожидание еле-еле спреды перебивают. Да я думаю, практически у любого разработчика есть такие стратегии, которые это подтвердят. Есть даже роботы в маркете, которые по всем параметрам — Граали. Но заработать на таких системах все равно крайне трудно, нужно выцарапывать каждый пипс в буквальном смысле, подключать возврат спреда и партнерские программы. По настоящему Граали, которые имеют красивые профитки и небольшую нагрузку на депозит, по пальцам пересчитать.
Если уж вы сами хотите написать Грааль, то лучше посмотрите в сторону нейросетей. Если где и есть возможность добиться сверх прибылей, то только там. Можете также комбинировать всякую экзотику и брутфорс. Но лучше всего сразу принимайтесь за нейросети.
Как ни странно, ответ на вопрос, где искать Грааль и возможен ли он, настолько прост и очевиден для меня, что даже сомнений никаких нет после тонны советников, которых я сделал.
Советы простым трейдерам
Все хотят трех вещей:
- Добиться положительного матожидания
- Увеличить прибыль в случае прибыльной позиции
- Уменьшить убыток в случае проигрышной позиции
На самом деле первый пункт краеугольный. Если у вас есть прибыльная стратегия и неважно, торгуете вы руками или советником, всегда существует желание вмешаться в торговлю так, что все пойдет не по сценарию. Этого нельзя допускать. Очень большое психологическое влияние оказывают ситуации, когда прибыльных сделок сильно меньше чем проигрышных. Это морально давит на трейдера и сводит всю систему на нет. Не нужно стараться выйти в плюс, когда вы в минусе — это главный момент. Оно вам абсолютно ничего не даст, кроме нервов и лишних убытков. Нужно помнить о матожидании и не важно какой сейчас убыток по эквити у текущей позиции, важно то, сколько этих позиций будет в итоге и сколько прибыльных противопоставим им.
Второй очень важный момент — это лот, которым вы играете. Выигрываем, значит постепенно понижаем лот, проигрываем значит наоборот постепенно увеличиваем лот. Но вот увеличивать его только до какого то крайнего значения. Это прямой и обратный мартингейл. Если вы хорошенько подумаете, то сможете написать свой советник, который работает только на варьировании лота. И это будет уже не сетка и не мартингейл, а нечто большее и, вдобавок, безопасное. И что самое главное, работающее на всех валютных парах по всей истории котировок. Этот принцип работает даже на хаотичном рынке, и неважно — где и как вы входите. При грамотном использовании вы скомпенсируете все спреды и комиссии, а при мастерском использовании выйдете в плюс даже при условии. что открываетесь вообще в рандомных местах и в рандомную сторону.
Третий момент тоже важен. Чтобы уменьшить убыток и увеличить прибыль, старайтесь открывать позизию в покупку на отрицательной полуволне, а в продажу на положительной полуволне. Дело в том, что полуволна в большинстве случаев сигнализирует о том, что на данном участке были активны либо продавцы либо покупатели, а это в свою очередь значит, что какой-то процент из них были рыночными на открытие позиции, а позиции, которые открыты, рано или поздно закроются, что будет двигать цену в противоположную сторону. Именно поэтому рынок имеет волновую структуру. И эти волны мы видим везде. За покупкой следует продажа и наоборот. Так же сами закрывайте позицию по тому же самому критерию.
Заключение
В конце скажу, что все, конечно, субъективно и каждый смотрит со своей колокольни. В итоге все зависит от вас, так или иначе. Но при всех минусах и потраченом времени, всем также хочется создать свою супер систему и пожинать плоды своего упрямства. Иначе я вообще не понимаю, зачем идти на форекс. Опыт бесценный, а денег минимум. Но есть что-то притягательное в этом, что не дает мне уйти из этой сферы, как и другим. Все знают, как это назвать, но звучать будет по детски. Поэтому, наверное, не буду это озвучивать, чтобы не затролили ).
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Статья с рекомендациями по сеткам и мартинам. Да это смерть депозиту !
Поясняю на примере. При оптимизации таких стартегийпараметры подбираются таким образом, чтоб пройти сложный участок. Т.е. в начале участка у нас нет позиций а в самый критичный момент количество позиций и лотов максимальное. НА реальном счете подойти к недачному участку рынка без накопленных позиций вряд ли удастся. отсюда слив. Новая оптимизация и опять слив.
Вы невнимательно читали. я писал что матожидание мартина и сетки "0" . Пожалуй наверное придется написать отдельную статью почему голый мартин и и сетка это слив ). Я даже подумывал об этом последнее время. Есть мартины и сетки в маркете прибыльные, вы просто внимательно поищите. Но никто не говорил что там фильтров нет. Я лишь сказал что что то работающее по глобальной истории я видел только на этих принципах.
"Просто не учи физику в школе, и вся твоя жизнь будет наполнена чудесами и волшебством")
Уже поздно не учить))))
Отличная статья! Спасибо!
Благодарю, с момента выхода этой статьи много других статей написал, почитайте, может еще что полезное найдете.