Применение статистического анализа к внутридневной торговле на рынке Форекс с использованием 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;
С разбросом в минимальном и максимальном закрытии:
SELECT d, AVG(c) AS avgc, MIN(c) AS minc, MAX(c) AS maxc
FROM gbpusd
group BY d
ORDER BY d;
Интересно попытаться наложить дни друг на друга, чтобы попытаться найти общее поведение цены в течение дня. Мы можем получить средние значения по запросу:
SELECT t, AVG(c) AS avgc
FROM gbpusd
GROUP BY t
ORDER BY t;
Здесь можно выделить период, когда цена находится на минимуме (красный), подходящем для открытия длинной позиции (покупка), и на максимуме (зеленый), когда эту длинную позицию можно закрыть. Вы также можете увидеть, что есть момент, когда цена еще ниже, и где кажется, что прибыли будет больше, но визуально этот период выглядит как период высокой волатильности, и вам нужно проверить, насколько сложно будет поймать цену в этот момент.
Кроме того, не совсем корректно навязывать абсолютные значения цен, и необходимо выполнять нормализацию.
С помощью 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
;
Получилась некая усредненная "картинка дня". Визуально легко найти минимумы и максимумы. Кажется, что вы можете открывать позиции в 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
;
Не очень много, но тем не менее положительная тенденция есть.
Но лучше найти максимальную разницу. Для этого будет удобнее создать отдельную таблицу:
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
;
И, наконец, запрос, имитирующий торговлю:
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;
Выводы
В целом можно отметить наличие некоторых паттернов цены время от времени в течение дня, хотя использовать их для корректной торговли достаточно сложно. Как всегда, необходимо учитывать множество факторов.
Какие есть подводные камни:
- Плавающий спред. Я взял минимальный спред, равный 1 пипсу. Но по мере его увеличения прибыль резко падает, и на 5 пипсах уходит в 0.
- Чем дольше мы держим позиции, тем выше вероятность наступления событий, которые приведут к сильному изменению цены, а значит, срабатывание стоп-лосса или маржин-колла.
- У вас должен быть достаточный баланс, чтобы противостоять потерям, особенно при торговле с большим кредитным плечом. По мере увеличения кредитного плеча риски увеличиваются в геометрической прогрессии.
Интересно рассмотреть эту статистику по различным валютным парам, а также изучить закономерности дня недели, возможно, есть более сильные периодические колебания.
Все зависит от конкретных условий, но если попробовать перебрать различные валютные пары с учетом условий конкретного брокера, то можно попробовать реализовать стратегию.
Оригинал