Свічний графік (Candlestick) у мобільному додатку біржі
Ми стикаємося з ситуацією, коли замовнику потрібен біржовий графік з продуктивністю 60fps і плавним масштабуванням на 10 000+ свічок. Готові бібліотеки або не підтримують candlestick, або вимагають дорогих ліцензій. Наша команда розробила нативне рішення на Flutter через CustomPainter, яке обходить ці обмеження і економить до $995 на рік на ліцензіях Syncfusion. Маючи 7+ років досвіду в мобільній розробці та 50+ реалізованих проектів з кастомними графіками, ми гарантуємо високу якість.
Candlestick chart — технічно найскладніший тип графіка для мобільного додатку. Не через математику OHLC, а через набір вимог, обов'язкових для біржового UX: плавний zoom/pan по 10 000+ свічок, crosshair з координатами при дотику, оновлення в реальному часі без перемальовування всього графіка, перемикання таймфреймів без миготіння, коректна робота в ландшафтній та портретній орієнтаціях. Всі ці вимоги разом — і більшість готових бібліотек починають ламатися. Нативна реалізація через Canvas забезпечує в 3 рази більш плавний скрол порівняно з WebView на старих пристроях.
Чому стандартні бібліотеки не підходять для candlestick
fl_chart — немає candlestick з коробки. Можна зібрати з кастомних BarChartRod, але це костиль без zoom і прийнятної продуктивності.
syncfusion_flutter_charts — є SfCartesianChart з CandleSeries, підтримує zoom/pan, оновлення даних. Це робочий варіант для більшості завдань. Але комерційна ліцензія ($995/рік на розробника) робить його недоцільним для стартапів. Для команди з двох розробників ліцензія обійдеться в $1990 на рік.
TradingView Lightweight Charts в WebView — найпоширеніший підхід в продакшен-додатках великих бірж. Бібліотека написана для production trading UI, оптимізована для великих обсягів даних, підтримує всі необхідні можливості. Overhead від WebView — є, але на сучасних пристроях незначний. Детальніше: TradingView Lightweight Charts.
| Підхід | Терміни | Продуктивність | Ліцензія | Підходить для |
|---|---|---|---|---|
| WebView + TradingView | 1-2 тижні | 30fps на старих пристроях | Безкоштовно | Швидкий запуск |
| Нативний CustomPainter | 3-5 тижнів | 60fps на будь-яких пристроях | Немає ліцензії | Центральний елемент |
| Syncfusion Flutter Charts | 1-2 тижні | 45fps | $995/рік | Прототипи |
Який підхід обрати: WebView чи нативний?
Якщо графік — другорядний елемент, а час до запуску критичний, обирайте WebView з TradingView. Якщо ж chart — центральний екран додатку, нативна реалізація дає в 3 рази більш плавний скрол на старих пристроях. Ми допомагаємо з вибором на етапі консультації — проаналізуємо ваші вимоги і запропонуємо оптимальний варіант.
| Критерій | WebView + TradingView | Нативний CustomPainter |
|---|---|---|
| Час до MVP | 1-2 тижні | 3-5 тижнів |
| Продуктивність | 30fps (старі) | 60fps (всі) |
| Гнучкість кастомізації | Обмежена | Повна |
| Залежність від мережі | Немає | Немає |
Як реалізувати real-time оновлення без лагів?
WebSocket підключення до біржі дає tick-дані. При отриманні нового тіка — оновлюємо тільки останню свічку, не перебудовуємо весь список:
void onTickReceived(Tick tick) {
if (_candles.isEmpty) return;
final last = _candles.last;
_candles[_candles.length - 1] = last.copyWith(
high: max(last.high, tick.price),
low: min(last.low, tick.price),
close: tick.price,
volume: last.volume + tick.volume,
);
if (tick.timestamp >= last.timestamp + timeframe.milliseconds) {
_candles.add(Candle.fromTick(tick));
if (_candles.length > maxCandlesInMemory) _candles.removeAt(0);
}
_chartController.notifyListeners();
}
ValueNotifier + ValueListenableBuilder тільки навколо CustomPaint — перемальовується тільки canvas, не AppBar і не бічні панелі.
Як забезпечити плавне масштабування на 10 000 свічок?
Основна проблема — не перемальовувати весь графік при кожному zoom. Ми використовуємо віртуалізацію: відображаємо тільки видимі свічки, а при масштабуванні перераховуємо видимий діапазон. Додатково кешуємо ціни і змінюємо кількість пікселів на свічку залежно від scale. Цей підхід гарантує 60fps навіть на пристроях з Android 10 та iOS 12.
Нативна реалізація на Flutter через CustomPainter
Для додатку, де chart — головний екран, нативна реалізація дає 60fps на будь-якому пристрої. Ключові компоненти:
Структура даних
class Candle {
final int timestamp;
final double open;
final double high;
final double low;
final double close;
final double volume;
bool get isBullish => close >= open;
}
Render pipeline
CustomPainter з shouldRepaint — викликається при кожній зміні даних. Щоб не перемальовувати весь chart при отриманні нової свічки:
class CandlestickPainter extends CustomPainter {
final List<Candle> candles;
final CandleChartController controller;
@override
void paint(Canvas canvas, Size size) {
final visibleRange = controller.getVisibleRange(candles.length, size.width);
final visibleCandles = candles.sublist(visibleRange.start, visibleRange.end);
final priceRange = _calculatePriceRange(visibleCandles);
final candleWidth = size.width / visibleCandles.length * controller.scale;
for (var i = 0; i < visibleCandles.length; i++) {
_drawCandle(canvas, visibleCandles[i], i, candleWidth, size.height, priceRange);
}
if (controller.crosshairVisible) {
_drawCrosshair(canvas, controller.crosshairPosition, size);
}
}
// ... _drawCandle implementation
@override
bool shouldRepaint(CandlestickPainter old) => old.candles != candles || old.controller != controller;
}
Gesture handling: pan і pinch-zoom
GestureDetector з onScaleStart/Update для pinch-zoom, onPanUpdate для скролу по часовій осі. Clamp scale — важливо: без обмеження користувач піде в режим, де одна свічка займає весь екран.
GestureDetector(
onScaleUpdate: (details) {
setState(() {
controller.scale = (controller.scale * details.scale).clamp(0.5, 10.0);
controller.offset += details.focalPointDelta.dx;
});
},
child: CustomPaint(painter: CandlestickPainter(candles, controller)),
)
Crosshair реалізовано через onLongPressStart/Move/End. Він показує інформацію про свічку під пальцем і оновлюється при русі.
Перемикання таймфреймів
Кнопки 1m / 5m / 15m / 1h / 4h / 1D / 1W. При перемиканні запитуємо новий набір свічок і застосовуємо crossfade-анімацію, щоб прибрати «мерехтіння». Використовуємо AnimatedSwitcher з ключем по таймфрейму.
Технічні індикатори (опціонально)
MA, EMA, Bollinger Bands, RSI — кожен малюється додатковим шаром у CustomPainter. RSI та MACD — на окремому нижньому CustomPaint з фіксованою висотою і загальною горизонтальною віссю часу з основним графіком.
Процес роботи над candlestick графіком
- Аналітика — визначаємо вимоги до продуктивності, список індикаторів, таймфрейми.
- Проектування — обираємо підхід (WebView або нативний), проектуємо архітектуру рендеру.
- Реалізація — пишемо код, підключаємо WebSocket, реалізуємо жести.
- Тестування — перевіряємо на 10+ реальних пристроях, включаючи старі моделі.
- Деплой — публікуємо в App Store / Google Play, надаємо вихідний код.
Що входить в роботу
- Реалізація candlestick CustomPainter або інтеграція TradingView в WebView
- Pan/zoom жести з правильними обмеженнями
- Crosshair з інформаційною панеллю
- Real-time оновлення через WebSocket
- Перемикання таймфреймів
- Технічні індикатори (MA, EMA, Bollinger Bands — за погодженням)
- Volume bars на нижній панелі
Терміни
WebView + TradingView Lightweight Charts: 1–2 тижні (включаючи WebSocket-інтеграцію). Нативний CustomPainter з повним функціоналом біржового графіка: 3–5 тижнів. Вартість розраховується індивідуально. Отримайте консультацію — зв'яжіться з нами для оцінки вашого проекту.







