Реалізація сповіщень про ціни криптовалют (Price Alerts) у мобільному додатку

TRUETECH займається розробкою, підтримкою та обслуговуванням мобільних додатків iOS, Android, PWA. Маємо великий досвід та експертизу для публікації мобільних додатків до популярних маркетів Google Play, App Store, Amazon, AppGallery та інші.

Розробка та підтримка будь-яких видів мобільних додатків:

Інформаційні та розважальні мобільні програми
Новинки, ігри, довідники, онлайн-каталоги, погодні, фітнес та здоров'я, туристичні, освітні, соціальні мережі та месенджери, квіз, блоги та подкасти, форуми, агрегатори
Мобільні програми електронної комерції
Інтернет-магазини, B2B-додатки, маркетплейси, онлайн-обмінники, кешбек-сервіси, біржі, дропшиппінг-платформи, програми лояльності, доставка їжі та товарів, платіжні системи
Мобільні програми для управління бізнес-процесами
CRM-системи, ERP-системи, управління проектами, інструменти для команди продажів, облік фінансів, управління виробництвом, логістика та доставка, управління персоналом, системи моніторингу даних
Мобільні програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, платформи надання електронних послуг, платформи кешбеку, відеохостинги, тематичні портали, платформи онлайн-бронювання та запису, платформи онлайн-торгівлі

Це лише деякі з типів мобільних додатків, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Послуги, які ми пропонуємо
Показано 1 з 1Усі 1735 послуг
Реалізація сповіщень про ціни криптовалют (Price Alerts) у мобільному додатку
Середній
~2-3 дні
Часті запитання

Наші компетенції:

Етапи розробки

Останні роботи

  • image_mobile-applications_feedme_467_0.webp
    Розробка мобільного додатка для компанії FEEDME
    792
  • image_mobile-applications_xoomer_471_0.webp
    Розробка мобільного додатку для компанії XOOMER
    671
  • image_mobile-applications_rhl_428_0.webp
    Розробка мобільного додатку для компанії RHL
    1097
  • image_mobile-applications_zippy_411_0.webp
    Розробка мобільного додатку для компанії ZIPPY
    969
  • image_mobile-applications_affhome_429_0.webp
    Розробка мобільного додатку для компанії Affhome
    914
  • image_mobile-applications_flavors_409_0.webp
    Розробка мобільного додатку для компанії FLAVORS
    495

Реалізація уведомлень про ціни криптовалют в мобільному додатку

Price Alerts — класично проста на вид завдання: користувач ставить ціну, при досягненні якої приходить сповіщення. На практиці це real-time система з ціновим стримом, логікою триггерів та гарантованою доставкою push. Головне питання архітектури — де перевіряти умови: на сервері чи на клієнті.

Серверна vs клієнтська перевірка

Клієнтська — додаток у фоні опитує ціну та порівнює з порогом. Не працює: iOS вбиває фонові процеси за кілька хвилин, Android без foreground service — також. Непридатно для production.

Серверна — єдино правильний варіант. Сервер отримує ціновий стрим, перевіряє алерти всіх користувачів, при срабатуванні отправляє push. Клієнт лише створює/видаляє алерти та отримує сповіщення.

Ціновий стрим: джерела даних

Варіанти для отримання real-time цін:

Джерело Протокол Затримка Покриття
Binance WebSocket WSS < 100ms Всі торгові пари Binance
CoinGecko API REST polling 30–60 сек 10,000+ монет
CryptoCompare WebSocket WSS < 500ms Агрегація бірж
Coinbase Advanced Trade WSS < 200ms Лише пари Coinbase

Для real-time алертів — WebSocket. Для менш срочних — polling.

Бекенд підписується на Binance WebSocket:

// Node.js — підписка на ціни через Binance WebSocket
const WebSocket = require('ws');

const PAIRS = ['btcusdt', 'ethusdt', 'solusdt'];
const ws = new WebSocket(`wss://stream.binance.com:9443/stream?streams=${PAIRS.map(p => p + '@ticker').join('/')}`);

ws.on('message', (data) => {
    const { stream, data: ticker } = JSON.parse(data);
    const symbol = stream.replace('@ticker', '').toUpperCase();
    const price = parseFloat(ticker.c); // поточна ціна

    priceCache.set(symbol, price);
    alertEngine.checkAlerts(symbol, price);
});

Рушій алертів

При кожному оновленні ціни — перевіряємо всі активні алерти для цієї пари:

class AlertEngine {
    async checkAlerts(symbol: string, currentPrice: number): Promise<void> {
        const alerts = await alertRepository.getActiveAlerts(symbol);

        const triggered = alerts.filter(alert => {
            if (alert.type === 'ABOVE') return currentPrice >= alert.targetPrice;
            if (alert.type === 'BELOW') return currentPrice <= alert.targetPrice;
            if (alert.type === 'PERCENT_CHANGE') {
                const change = Math.abs((currentPrice - alert.basePrice) / alert.basePrice * 100);
                return change >= alert.percentThreshold;
            }
            return false;
        });

        for (const alert of triggered) {
            await this.fireAlert(alert, currentPrice);
        }
    }

    private async fireAlert(alert: PriceAlert, price: number): Promise<void> {
        // Деактивуємо алерт щоб не дублювати сповіщення
        await alertRepository.deactivate(alert.id);

        // Отправляємо push
        await pushService.sendToUser(alert.userId, {
            title: `${alert.symbol} досяг ${formatPrice(price)}`,
            body: this.buildAlertMessage(alert, price),
            data: { screen: 'price_detail', symbol: alert.symbol }
        });

        // Зберігаємо в історію
        await alertRepository.saveTriggeredAlert(alert, price);
    }
}

Деактивація до надсилання push — важливо. Якщо push-надсилання зафейлиться та буде retry, алерт уже деактивований — нема дублів.

Мобільний клієнт: створення алерту

// iOS — форма створення алерту
struct CreateAlertView: View {
    @State private var targetPrice: String = ""
    @State private var alertType: AlertType = .above
    let symbol: String
    let currentPrice: Double

    var body: some View {
        Form {
            Section("Умова") {
                Picker("Тип алерту", selection: $alertType) {
                    Text("Ціна вище").tag(AlertType.above)
                    Text("Ціна нижче").tag(AlertType.below)
                    Text("Зміна %").tag(AlertType.percentChange)
                }
                .pickerStyle(.segmented)

                HStack {
                    Text("$")
                    TextField("0.00", text: $targetPrice)
                        .keyboardType(.decimalPad)
                }
            }

            Section {
                Text("Поточна ціна: \(formatPrice(currentPrice))")
                    .foregroundColor(.secondary)
            }

            Button("Створити алерт") {
                createAlert()
            }
            .disabled(targetPrice.isEmpty)
        }
    }
}

Список активних алертів

Користувач повинен бачити всі свої алерти та управляти ними. Кожен алерт — відображення умови, поточної ціни щодо порога, кнопка видалення.

Для візуалізації близості до порога — progress indicator з поточною ціною між базовою та цільовою:

// Android — візуалізація відстані до порога
@Composable
fun AlertProgressBar(currentPrice: Double, targetPrice: Double, basePrice: Double) {
    val progress = ((currentPrice - basePrice) / (targetPrice - basePrice)).coerceIn(0.0, 1.0)
    LinearProgressIndicator(
        progress = progress.toFloat(),
        modifier = Modifier.fillMaxWidth(),
        color = if (progress > 0.8) Color.Orange else MaterialTheme.colorScheme.primary
    )
    Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
        Text(formatPrice(basePrice), style = MaterialTheme.typography.labelSmall)
        Text("Ціль: ${formatPrice(targetPrice)}", style = MaterialTheme.typography.labelSmall)
    }
}

Повторні алерти

За замовчуванням алерт срабатує один раз та деактивується. Користувач може вибрати "повторити" — тоді алерт реактивується через N хвилин після срабатування, щоб не спамити при volatile ринку:

if (alert.isRepeating) {
    const cooldownMs = alert.cooldownMinutes * 60 * 1000;
    await alertRepository.scheduleReactivation(alert.id, Date.now() + cooldownMs);
}

Графік

Реалізація серверного рушія алертів з WebSocket ціновим стримом (Binance/CryptoCompare), мобільний UI створення/управління алертами, push при срабатуванні з історією — 8–12 робочих днів.