Grid Bot Mobile App
A Grid bot places a grid of orders above and below the current price: sells at each level up, buys at each level down. The management interface for such a bot requires grid visualization—user should see where orders are placed, which have filled, what PnL each level brought.
Grid Strategy Parameters
Minimum set of parameters to configure:
- Range—lower and upper bounds of the grid in USDT (for example, 60,000 – 70,000 for BTC)
- Number of levels—10 levels means step (70,000 − 60,000) / 10 = $1,000
- Order size—$100 per level
- Grid type—arithmetic (equal step in USD) or geometric (equal step in %)
Geometric grid is correct for volatile assets: $500 step makes sense at BTC $10,000 but is negligible at $60,000. With geometric grid, levels are calculated as lower * (upper/lower)^(i/n).
// Android — calculate grid levels
fun calculateGridLevels(
lower: Double,
upper: Double,
count: Int,
type: GridType
): List<Double> = when (type) {
GridType.ARITHMETIC -> {
val step = (upper - lower) / count
(0..count).map { i -> lower + step * i }
}
GridType.GEOMETRIC -> {
val ratio = (upper / lower).pow(1.0 / count)
(0..count).map { i -> lower * ratio.pow(i.toDouble()) }
}
}
User enters range and number of levels—app immediately shows preview: here are the levels, here is the step between them, here is total capital needed for all orders.
Grid Visualization
This is the main UI challenge. A custom widget is needed: horizontal lines of grid levels on top of price chart. Filled orders—green/red markers. Current price—pulsing line.
On Flutter this is CustomPainter:
class GridChartPainter extends CustomPainter {
final List<GridLevel> levels;
final List<PricePoint> priceHistory;
final double currentPrice;
@override
void paint(Canvas canvas, Size size) {
final priceRange = levels.last.price - levels.first.price;
final priceToY = (double price) =>
size.height - (price - levels.first.price) / priceRange * size.height;
// Draw grid levels
for (final level in levels) {
final y = priceToY(level.price);
final paint = Paint()
..color = level.hasFilled ? Colors.green.withOpacity(0.3) : Colors.grey.withOpacity(0.2)
..strokeWidth = 1;
canvas.drawLine(Offset(0, y), Offset(size.width, y), paint);
// Price label
final tp = TextPainter(
text: TextSpan(text: level.price.toStringAsFixed(0), style: const TextStyle(fontSize: 10)),
textDirection: TextDirection.ltr,
)..layout();
tp.paint(canvas, Offset(4, y - 12));
}
// Price line
final pricePaint = Paint()..color = Colors.blue..strokeWidth = 1.5;
for (int i = 1; i < priceHistory.length; i++) {
canvas.drawLine(
Offset(size.width * (i-1) / priceHistory.length, priceToY(priceHistory[i-1].price)),
Offset(size.width * i / priceHistory.length, priceToY(priceHistory[i].price)),
pricePaint,
);
}
}
@override
bool shouldRepaint(GridChartPainter old) =>
old.currentPrice != currentPrice || old.levels != levels;
}
Grid Bot Statistics
Grid PnL—total income from executed order pairs (buy at lower level, sell at upper level). Each filled pair brings grid_step × order_size. With 10 levels and $1,000 step: each round trip = $1,000 profit per $100 order.
Floating PnL—unrealized profit/loss from price going outside the range. If BTC drops below the grid's lower bound—the bot holds all bought orders at loss until price returns to range.
Also show: number of filled order pairs, count of active orders now, capital deployed.
What's Included
- Settings form with grid type selection and level preview
- Custom widget for grid visualization (CustomPainter)
- Dashboard: Grid PnL, Floating PnL, number of filled pairs
- Executed order history with grouping by pairs
- Real-time order status update via WebSocket
Timeline
6–8 business days—custom grid widget takes significant time. Cost is calculated individually after requirements analysis.







