Исходный код, разобранный в статье, опубликован в этом репозитории.

Усреднение цены актива
В трейдинге есть такой подход как усреднение цены актива. Допустим, мы знаем инсайд, что Трамп зашитпостит хорошую новость по ирану (если это будет плохая новость, интернет умрёт от ЭМИ импульса ядерной бомбы). И мы покупаем биткоин заранее на слухах, чтобы продать хомяку на новостях

При этом, мы сможем снять только сырое движение рынка. Рынок двинулся от 65,820$ до 79,382$, это +15.3%. Если будем фиксировать прибыль частями, будет 12%. Положили 100$ в начале, в конце достали 112.45$. Мало за целый месяц ожидания

Можно сделать фокус. Рынок растет не линейно: единовременно есть просадки. Если цена начала падать, мы не продаём, а покупаем ещё раз

Кратко объясню математику. Монета стоила 100 рублей, потом 75 рублей, потом 50 рублей, потом 25 рублей. Если покупать монету на каждом упомянутом дне, средняя цена монеты для вас будет 62,5 рублей: простое среднее арифметическое. Это ровно по середине между 50 и 75 рублями

Вроде бы выглядит вкуснее. 12 процентов превратились в 19, а заработали 67.85$ вместо 12.45$. Так же, деньги работают, в оборот удалось применить не 100$, а 500$. Но есть нюанс

Даже при просадке цены -2.5% что нормальное колебание для Bitcoin, в фиате единовременно на счёте будет -10$. Брокер скажет вам, что деньги заморожены.
Всё идет по плану
За месяц, рекордная просадка по сделке 13.92% (−$50.41). Де факто, эти деньги не заморожены, их именно нет, брокер просто врёт, что всё идет по плану. Это потому, что на его dashboard отображаются только закрытые позиции: единовременная просадка портфеля посеит панику и вызовет массовый вывод средств.

Но что произойдёт, если прогноз по новостям не исполнится
Исходный код
/** * Усреднение */listenActivePing(async ({ symbol, currentPrice }) => { const { length: steps } = await getPositionEntries(symbol); if (steps >= LADDER_MAX_STEPS) { return; } const hasOverlap = await getPositionEntryOverlap(symbol, currentPrice, { upperPercent: LADDER_UPPER_STEP, lowerPercent: LADDER_LOWER_STEP, }); if (hasOverlap) { return; } await commitAverageBuy(symbol, LADDER_STEP_COST);});/** * Закрытие */listenActivePing(async ({ symbol, data, timestamp }) => { console.log(new Date(timestamp)); const currentProfit = await getPositionPnlPercent(symbol); if (currentProfit < TARGET_PROFIT) { return; } Log.info("position closed due to the target pnl reached", { symbol, data, }); await commitClosePending(symbol, { id: "unknown", note: str.newline( "# Позиция закрыта по target pnl", ), });});
Спасибо за внимание!
ссылка на оригинал статьи https://habr.com/ru/articles/1029538/