Можно ли обыграть казино? Можно. Но на чьей стороне статистика?
Напоминание: Бинарные опционы — это азартная игра. Опасно надеяться на честность брокера и удачу. Возможна манипуляция с потоком истории цен. Поехали!
Условия «вакуума»
Казино всегда накладывает дополнительные ограничения на игроков. Иногда ограничения связаны с внешними обстоятельствами. Всё это мы будем игнорировать.
- Минимальная ставка 1000 руб.
- Коэффициент прибыли 0.82%.
- Пара EUR/USD.
- Пробуем делать ставку каждую минуту.
- Дожи фильтруем при разнице менее 0,005%.
- Мартингейл должен покрыть убыток и принести прибыль первой ставки.
- Условия принимаются по текущей свече. Если свеча зелёная, делаем ставку на рост, если красная — на падение.
Тесты
Историю цен можно найти в интернете бесплатно. Ниже на графиках минутные свечи за первую неделю и распределение величины свечей для фильтрации дожи.
Первые тесты без Мартингейла пропуская дожи показывают стабильное поражение. Слева — баланс, справа — просадка в долях.
Добавим Мартингейл и видим стабильный рост баланса. Только всё омрачает пикирование в периоды увеличения ставки на проигрышах.
На графиках видно, что падение может достигать 40х кратной просадки. Сказать, что это много, ничего не сказать. Но есть периоды, когда в течение недели баланс сопровождает удача. Кому-то везёт, кому нет.
Теперь к Мартингейлу добавим простые технические индикаторы, показывающие направление тренда. Они запаздывают, но помогают фильтровать неблагоприятные моменты.
Отфильтруем по RSI(10): выше 60 — разрешено ставить на рост, ниже 40 — на падение.
Как мы видим максимальная просадка незначительно сократилась, а ставки стали безобиднее. Всего лишь миллион.
Последний тест с пересечением средних. Короткая над длинной — рост, наоборот — падение.
Всё хорошо, если бы не один раз и на повал.
Таблица с результатами:
- profit/loss — итоговый результат.
- max drawdown, % — максимальная просадка в процентах.
- max win — максимальный выигрыш.
- max loss — максимальный проигрыш.
- bets — количество ставок.
- wins — количество выигрышных ставок.
- loss — количество проигрышных ставок.
- candles — количество баров.
Событийно-ориентированный бэктестер
Это относительно медленный бэктестер, который позволяет тестировать историю цен исключая заглядывание в будущее. За счёт топорности содействует легкому поиску ошибок. Для его работы нам требуется:
- Класс (Account), отвечающий за баланс и обработку ставки.
- Функция (simple), вызываемая на каждой свече, работающая с прошлой историей.
- Pandas датафрейм с OHLC историей цен.
Account
Здесь всё просто. Следим за балансом, принимаем и проверяем ставки.
class Account(object): def __init__(self, bet_profit=0.82): self._bet = None self.equity = [] self.loss = [] self.bet_profit = 0.82 def bet(self, direction=None, amount=None, ts=None): self._bet = {'direction': direction, 'amount': amount, 'ts': ts} def tick(self, ticks): result = 0 if self._bet is not None and self._bet['direction'] is not None: if self._bet['direction'] > 0 and ticks.close[-1] > ticks.close[-2]: result = self._bet['amount'] * self.bet_profit self.equity.append({'ts': ticks.index[-1], 'amount': result}) self.loss = [] elif self._bet['direction'] < 0 and ticks.close[-1] < ticks.close[-2]: result = self._bet['amount'] * self.bet_profit self.equity.append({'ts': ticks.index[-1], 'amount': result}) self.loss = [] else: result = -self._bet['amount'] self.equity.append({'ts': ticks.index[-1], 'amount': result}) self.loss.append(result) # reset bet self.bet() return result, np.sum(self.loss)
Побарный цикл
Эту функцию мы передадим в метод pd.Dataframe().apply(), чтобы через неё прошли все имеющиеся ценовые бары. Дополнительно, сопроводим каждый бар объектом account и полной историей цен. В начале функции добавим фильтр данных по дате текущего бара, чтобы отсечь будущее.
def simple(tick, data=None, account=None, skip_dogi=False, martingale=False): if account is None: print('Account is not available') return 0 fltr = data.index <= tick.ts # send last ticks to account result, loss = account.tick(data[fltr][-5:].copy()) amount = 1000 if martingale: if loss < 0: amount += abs(loss) / account.bet_profit if skip_dogi and tick.dogi <= 0.00005: pass elif tick.open > tick.close: # sell on red account.bet(-1, amount=amount, ts=tick.ts) elif tick.open < tick.close: # buy on green account.bet(1, amount=amount, ts=tick.ts) return result
Запуск
Осталось подготовить данные и запустить.
df = pd.read_csv('DAT_MT_EURUSD_M1_201807.csv', names=['date', 'time', 'open', 'high', 'low', 'close', 'volume']) # ... df = df[['ts', 'open', 'high', 'low', 'close']].set_index('ts', drop=False).sort_index() df['dogi'] = (df.close / df.open - 1).abs() account = Account() results = df.apply(partial(simple, data=df, account=account, skip_dogi=True), raw=False, axis=1)
Заключение
Мы рассмотрели грааль на основе Мартингейла, при условии бесконечного капитала. В реальности результаты будут чуть хуже. Брокеры, предлагающие подобное развлечение находятся вне регулируемого поля и у них существует множество методов обмана игрока.
Рассмотренный бэктестер можно использовать для тестирования простых стратегий на любых финансовых инструментах. Необходимо лишь доработать метод исполнения и проверки решения.
Источник