Применение статистического анализа к внутридневной торговле на рынке Форекс с использованием SQL

Применение статистического анализа к внутридневной торговле на рынке Форекс с использованием SQL

20 декабря 2022 г.

Если вы интересовались финансовыми рынками, а в частности Форекс, и если это была внутридневная торговля, то думаю этот материал будет вам интересен. Вы, наверное, замечали, что динамика рыночных цен иногда ведет себя одинаково в разные моменты времени в течение дня.

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

Если предположить, что в течение дня есть время, когда цена достигает пика, а также время, когда она находится на минимуме, то можно попытаться совершить соответствующие сделки, чтобы получить прибыль.

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

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

Попробуем проанализировать валютную пару GBPUSD и проверить нашу теорию несколько необычным способом, используя SQL для сбора статистики. Я взял минутные бары GBPUSD за 2021 год, всего около 373к записей (1440 минутных баров в день, около 260 торговых дней).

Для тех, кто может не знать, бар — это комбинация чисел OHLC — значений уровней открытия, максимума, минимума и закрытия. Кроме того, конечно, есть время бара, а также объем торгов. Если ориентироваться на диапазон от Low до High, можно получить более выгодную разницу курсов в течение дня, но в этом случае нам придется отслеживать эти максимумы и минимумы, ставить плавающие стоп-лоссы или использовать любые другие способы отслеживать момент закрытия позиции.

Мы хотим получить точные значения времени, когда мы можем открыть и закрыть позицию, поэтому сосредоточимся на цене закрытия.

Я взял данные одного из брокеров и экспортировал данные о курсах с платформы Metatrader.

Пример записи:

2021.11.19  17:01:00    1.34520 1.34530 1.34460 1.34463 178 0   3

Далее я создал таблицу в базе данных и загрузил в нее данные (здесь я использую MySQL):

CREATE TABLE test.gbpusd (
  d date,
  t time,
  o decimal(8, 5),
  h decimal(8, 5),
  l decimal(8, 5),
  c decimal(8, 5),
  v int
);

Мы можем добавить пару индексов:

ALTER TABLE test.gbpusd ADD INDEX IDX_gbpusd_d (d);
ALTER TABLE test.gbpusdADD INDEX IDX_gbpusd_t (t);

Посмотрим, сколько у нас данных:

SELECT COUNT(DISTINCT DAYOFYEAR(d)) FROM gbpusd;

У нас есть 260 торговых дней. Динамика в течение года:

SELECT d, AVG(c) AS avgc
FROM gbpusd
group BY d
ORDER BY d;

Average close price throughout the year

С разбросом в минимальном и максимальном закрытии:

SELECT d, AVG(c) AS avgc, MIN(c) AS minc, MAX(c) AS maxc
FROM gbpusd
group BY d
ORDER BY d;

Average, min and max close price throughout the year

Интересно попытаться наложить дни друг на друга, чтобы попытаться найти общее поведение цены в течение дня. Мы можем получить средние значения по запросу:

SELECT t, AVG(c) AS avgc
FROM gbpusd
GROUP BY t
ORDER BY t;

Average close price in absolute values

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

Кроме того, не совсем корректно навязывать абсолютные значения цен, и необходимо выполнять нормализацию.

С помощью SQL возьмем минимум и максимум за каждый день и рассчитаем процентное значение цены закрытия каждого бара:

SELECT t, AVG((c - minc) / (maxc - minc)) AS avgc
FROM (
    SELECT d, t, c,
      MAX(c) OVER(PARTITION BY d) AS maxc,
      MIN(c) OVER(PARTITION BY d) AS minc
    FROM gbpusd
) a
GROUP BY t
ORDER BY t
;

Average close price in normalized values

Получилась некая усредненная "картинка дня". Визуально легко найти минимумы и максимумы. Кажется, что вы можете открывать позиции в 00:30 и закрывать в 10:35. Давайте проанализируем, какую прибыль можно было бы получить, если бы мы совершали сделки одновременно:

SELECT
    SUM(IF((b.c - a.c - @spread) > 0, 1, 0)) profits,
    SUM(IF((b.c - a.c - @spread) > 0, 0, 1)) losses,
    ROUND(SUM(IF((b.c - a.c - @spread) > 0, 1, 0)) / COUNT(1) * 100, 2) AS profits_pct,
    ROUND(SUM((b.c - a.c - @spread) * @lot * @leverage), 2) total_profit
FROM
(SELECT @equity := 1000.00000, @spread := 0.0001, @lot := 100, @leverage := 100) AS init,
(SELECT d, c FROM gbpusd WHERE t = '00:30:00') a
JOIN
(SELECT d, c FROM gbpusd WHERE t = '10:35:00') b ON a.d = b.d
;

Не очень много, но тем не менее положительная тенденция есть.

Profits and losses

Но лучше найти максимальную разницу. Для этого будет удобнее создать отдельную таблицу:

CREATE TABLE gbpusd_avgnorm AS
SELECT t, AVG((c - minc) / (maxc - minc)) AS avgc
FROM (
    SELECT d, t, c, MAX(c) OVER(PARTITION BY d) AS maxc, MIN(c) OVER(PARTITION BY d) AS minc FROM gbpusd
) a
GROUP BY t
ORDER BY t;

Всего чуть больше миллиона комбинаций:

SELECT COUNT(*)
FROM gbpusd_avgnorm a
JOIN gbpusd_avgnorm b ON b.t > a.t
;

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

SELECT b.avgc - a.avgc, a.t, b.t
FROM gbpusd_avgnorm a
JOIN gbpusd_avgnorm b ON b.t > a.t
order BY 1 DESC
;

И мы видим, что комбинация 00:08 - 15:44 должна быть самой прибыльной:

SELECT
    SUM(IF((b.c - a.c - @spread) > 0, 1, 0)) profits,
    SUM(IF((b.c - a.c - @spread) > 0, 0, 1)) losses,
    ROUND(SUM(IF((b.c - a.c - @spread) > 0, 1, 0)) / COUNT(1) * 100, 2) AS profits_pct,
    ROUND(SUM((b.c - a.c - @spread) * @lot * @leverage), 2) total_profit
FROM
(SELECT @equity := 1000.00000, @spread := 0.0001, @lot := 100, @leverage := 100) AS init,
(SELECT d, c FROM gbpusd WHERE t = '00:08:00') a
JOIN
(SELECT d, c FROM gbpusd WHERE t = '15:44:00') b ON a.d = b.d
;

Most profitable combination

И, наконец, запрос, имитирующий торговлю:

SELECT
    a.d,
    b.c - a.c AS delta, (b.c - a.c) * 10000 AS profit,
    CAST((b.c - a.c - @spread) * 10000 AS decimal(10,2)) AS profit_with_spread,
    CAST(@equity := @equity + (b.c - a.c - @spread) * 10000 AS decimal(10,2)) AS equity
FROM
(SELECT @equity := 1000.00000, @spread := 0.0001) AS init,
(SELECT d, c FROM gbpusd WHERE t = '00:08:00') a
JOIN 
(SELECT d, c FROM gbpusd WHERE t = '15:44:00') b ON a.d = b.d
ORDER BY a.d;

Trading simulation

Выводы

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

Какие есть подводные камни:

  1. Плавающий спред. Я взял минимальный спред, равный 1 пипсу. Но по мере его увеличения прибыль резко падает, и на 5 пипсах уходит в 0.
  2. Чем дольше мы держим позиции, тем выше вероятность наступления событий, которые приведут к сильному изменению цены, а значит, срабатывание стоп-лосса или маржин-колла.
  3. У вас должен быть достаточный баланс, чтобы противостоять потерям, особенно при торговле с большим кредитным плечом. По мере увеличения кредитного плеча риски увеличиваются в геометрической прогрессии.

Интересно рассмотреть эту статистику по различным валютным парам, а также изучить закономерности дня недели, возможно, есть более сильные периодические колебания.

Все зависит от конкретных условий, но если попробовать перебрать различные валютные пары с учетом условий конкретного брокера, то можно попробовать реализовать стратегию.


Оригинал
PREVIOUS ARTICLE
NEXT ARTICLE