AWS Builder Center
Building a Risk-Controlled Crypto Arbitrage Platform on AWS EC

Building a Risk-Controlled Crypto Arbitrage Platform on AWS EC

nstead of building a simple “buy low, sell high” bot, the goal is to create a risk-controlled platform that starts with market analysis and paper trading, while keeping live trading optional and locked behind explicit safety checks.

Cloud DevOps Engineer @ The Cloud Advisory

BB-Arbitrage: Building a Risk-Controlled Crypto Arbitrage Platform on AWS EC2

BB-Arbitrage : Crypto Arbitrage Plateform Architecture on AWS

A practical walkthrough for building, containerizing, deploying, and monitoring a crypto arbitrage platform on AWS.

Crypto arbitrage sounds simple: buy an asset where it is cheaper and sell it where it is more expensive.
But there is a problem.
A price difference that looks profitable on a screen does not automatically mean there is real profit after trading fees, slippage, liquidity, latency, minimum order requirements, and execution failures.
That is why I designed BB-Arbitrage differently. Instead of building a simple “buy low, sell high” bot, the goal is to create a risk-controlled platform that starts with market analysis and paper trading, while keeping live trading optional and locked behind explicit safety checks.

What BB-Arbitrage Is Designed to Do

BB-Arbitrage is a cloud-ready crypto arbitrage platform designed to:
  • Collect real-time market data
  • Detect price differences
  • Calculate realistic expected profit
  • Include fees and estimated slippage
  • Check liquidity and exchange rules
  • Reject opportunities below the configured threshold
  • Simulate trades through paper trading
  • Backtest strategies using historical data
  • Track portfolio performance
  • Monitor system health
  • Provide optional spot-trading execution
  • Maintain an audit trail
The objective is not to promise profits.
The objective is to build a reliable trading-engineering platform where risk controls have priority over trade frequency.

Why a Simple Arbitrage Bot Isn't Enough

Imagine two exchanges showing:
1
2
3
4
5
6
7
Exchange A
BTC/USDT Buy = $100,000

Exchange B
BTC/USDT Sell = $100,200

Gross spread = 0.20%
At first glance, a 0.20% spread looks interesting.
But the gross spread is only the starting point.
A real system also needs to account for:
  • Trading fees
  • Bid/ask spread
  • Slippage
  • Liquidity
  • Minimum order requirements
  • Market-data latency
  • Partial fills
  • Network and execution costs
  • Exchange/API failures
  • Applicable taxes and other charges
For example:
1
2
Buy = $100,000
Sell = $100,250
That is a 0.25% spread.
But after costs:
1
2
3
4
5
Trading fees -0.20%
Slippage -0.04%
Other costs -0.02%
--------------------------------
Expected net -0.01%
The correct decision is:
1
DO NOT TRADE
This idea is central to BB-Arbitrage: an opportunity should be rejected when its expected economics do not satisfy the configured rules.

High-Level Architecture

The platform uses AWS EC2 and Docker as the initial deployment foundation.
The application is divided into several logical components:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
Internet
|
v
+----------------+
| Nginx / ALB |
+--------+-------+
|
v
+----------------+
| Frontend |
| Next.js / TS |
+--------+-------+
|
v
+----------------+
| FastAPI |
| Backend |
+--------+-------+
|
+---------------+----------------+
| | |
v v v
Market Engine Risk Engine Paper Trading
| | |
+---------------+----------------+
|
v
+----------------+
| Arbitrage |
| Engine |
+--------+-------+
|
+------------+-------------+
| |
v v
Redis PostgreSQL
| |
+------------+-------------+
|
v
Amazon S3
Reports / Backups /
Historical Data

AWS Services Used

The initial deployment intentionally keeps the AWS architecture relatively simple.

Amazon EC2

EC2 hosts:
  • Docker
  • FastAPI
  • Next.js
  • Redis
  • Nginx
  • Background workers
  • Monitoring components where appropriate

Amazon S3

S3 is used for object storage rather than transactional database storage.
Possible uses include:
  • Historical market-data files
  • Backtesting datasets
  • Generated reports
  • Application exports
  • Log archives
  • Database backups
  • Strategy-analysis reports

PostgreSQL

PostgreSQL stores transactional application data such as:
  • Users
  • Trades
  • Orders
  • Opportunities
  • Portfolio data
  • Risk events
  • Audit logs
  • Backtest metadata
For an MVP, PostgreSQL can run in Docker on EC2. A more production-oriented architecture can introduce Amazon RDS PostgreSQL later.

Redis

Redis handles:
  • Real-time state
  • Market-data caching
  • Rate limiting
  • Pub/sub
  • WebSocket coordination
Redis should not be treated as the permanent transaction ledger.

CloudWatch

CloudWatch can be used for:
  • EC2 monitoring
  • Application logs
  • System alerts
  • CPU, memory, and disk monitoring
  • Operational dashboards

Why Start With EC2?

For an early version, EC2 provides direct control over:
1
2
3
4
5
6
7
Docker
Networking
Nginx
Application processes
Background workers
Monitoring
Deployment
It is also useful when learning and demonstrating AWS and DevOps skills.
The platform can later evolve toward:
1
2
3
4
5
6
7
ECS
RDS
ElastiCache
Secrets Manager
Application Load Balancer
CloudWatch
ECR
The important point is that there is no need to introduce every AWS service on day one.

Step 1 — Create the EC2 Instance

Create an EC2 instance in an AWS Region close to your target users and exchange infrastructure.
For the MVP, the markdown specifies a small general-purpose Linux instance using:
1
Ubuntu Server LTS
Configure the security group to allow:
1
2
3
SSH 22 Your IP only
HTTP 80 Internet
HTTPS 443 Internet
Do not expose PostgreSQL or Redis publicly:
1
2
PostgreSQL 5432
Redis 6379
These should remain private to the application host or network.

Step 2 — Connect to EC2 and Install Docker

Connect to the server:
1
ssh -i your-key.pem ubuntu@YOUR_EC2_PUBLIC_IP
Update the system:
1
2
sudo apt update
sudo apt upgrade -y
Install Docker:
1
sudo apt install -y docker.io docker-compose-plugin
Enable Docker:
1
2
sudo systemctl enable docker
sudo systemctl start docker
Verify the installation:
1
2
docker --version
docker compose version

Step 3 — Clone the Project

Clone the repository:
1
2
3
git clone https://github.com/bhupendrabhati/BB-Arbitrage.git

cd bb-arbitrage
Create the environment configuration:
1
cp .env.example .env
Do not commit .env to Git.
Add:
1
.env
to .gitignore.

Step 4 — Configure Environment Variables

The initial configuration is intentionally conservative:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
APP_ENV=production

TRADING_MODE=paper

INITIAL_CAPITAL_INR=100

MAX_TRADE_AMOUNT_INR=10

MAX_DAILY_LOSS_INR=2

MAX_OPEN_TRADES=1

MAX_TRADES_PER_DAY=5

MIN_NET_PROFIT_INR=0.10

MAX_SLIPPAGE_PERCENT=0.05

STALE_DATA_MS=500

LIVE_TRADING_ENABLED=false
The important setting here is:
1
TRADING_MODE=paper
and:
1
LIVE_TRADING_ENABLED=false
The system starts without real-money execution.
Exchange credentials should remain outside source control. For production, the architecture recommends using AWS Secrets Manager rather than storing secrets directly in the repository or frontend.

Step 5 — Build and Start the Containers

Build the containers:
1
docker compose build
Start them:
1
docker compose up -d
Check their status:
1
docker compose ps
View logs:
1
docker compose logs -f

Step 6 — Understand the Docker Compose Architecture

A simplified deployment can contain:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
services:

backend:
build: ./backend
depends_on:
- postgres
- redis

frontend:
build: ./frontend

postgres:
image: postgres:16

redis:
image: redis:7

nginx:
image: nginx:latest
For production, tested image versions should be pinned rather than relying on moving latest tags.

Step 7 — Put Nginx in Front

Nginx can provide:
1
2
3
4
5
HTTPS
Reverse Proxy
Frontend routing
API routing
Security headers
The routing model is:
1
2
3
4
5
6
7
https://your-domain.com
↓
Next.js

https://your-domain.com/api
↓
FastAPI
Use HTTPS with a trusted certificate.

Step 8 — Connect a Domain

A domain can optionally be connected using:
1
2
3
Route 53
↓
EC2 / Load Balancer
For example:
1
app.example.com
The request flow becomes:
1
2
3
4
5
HTTPS
↓
Nginx
↓
Next.js / FastAPI

Step 9 — Configure Amazon S3

Create an S3 bucket such as:
1
bb-arbitrage-data
Use prefixes:
1
2
3
4
5
historical/
backtests/
reports/
exports/
backups/
Keep the bucket private.
Financial and trading data should not be publicly readable. IAM permissions should allow the application to access only the required bucket paths.

Step 10 — Upload Historical Data

For example:
1
2
aws s3 cp historical-data.csv \
s3://bb-arbitrage-data/historical/btc/
The backtesting engine can then download datasets when required.

Step 11 — Store Backtest Reports

A typical report workflow is:
1
2
3
4
5
6
7
Backtest
↓
Generate JSON/CSV report
↓
Upload to S3
↓
Store S3 object reference in PostgreSQL
This gives the application a clean separation:
1
2
3
4
5
PostgreSQL
→ metadata

S3
→ large files

The Trading Engine Behind the Deployment

Infrastructure is only one part of the project. The application itself contains several important components.

Market Data Engine

The market-data engine connects to supported exchanges and collects:
1
2
3
4
5
6
7
8
Exchange
Symbol
Bid
Ask
Bid Quantity
Ask Quantity
Timestamp
Sequence Number
Where possible, WebSockets should be used for real-time market data.
The engine should also reject stale data.
For example:
1
2
3
4
5
6
7
Current time: 18:20:01.500
Market timestamp: 18:20:01.100

Data age: 400ms

If threshold = 500ms
→ Data is acceptable
If the data becomes too old:
1
2
3
STALE DATA
↓
NO TRADE

Arbitrage Engine

The arbitrage engine compares market conditions.
For example:
1
2
3
4
5
6
7
BTC/USDT

Exchange A
Ask = $100,000

Exchange B
Bid = $100,250
The calculation follows:
1
2
3
4
5
6
7
8
9
10
11
Gross spread
↓
Trading fees
↓
Estimated slippage
↓
Liquidity
↓
Other configured costs
↓
Expected net profit
Only opportunities satisfying the configured rules proceed to the risk engine.

Risk Engine

The risk engine is one of the most important components.
Every trade must pass checks such as:
1
2
3
4
5
6
7
8
9
10
Capital limit
Trade-size limit
Daily loss limit
Open-position limit
Liquidity
Slippage
Data freshness
Exchange health
API health
Minimum order size
The initial example configuration is deliberately small:
1
2
3
4
5
INITIAL_CAPITAL_INR=100
MAX_TRADE_AMOUNT_INR=10
MAX_DAILY_LOSS_INR=2
MAX_OPEN_TRADES=1
MAX_TRADES_PER_DAY=5

Paper Trading

Paper trading allows the platform to use real market data without risking real capital.
The simulator should model:
  • Fees
  • Slippage
  • Order-book depth
  • Partial fills
  • Latency
  • Failed orders
  • Rejected orders
This matters because a naive paper-trading system can make results appear much better than they would be in real execution.

Backtesting

The backtesting engine evaluates strategies against historical data.
A report can include:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Initial Capital
Final Capital
Gross P&L
Fees
Slippage
Net P&L
Number of Trades
Winning Trades
Losing Trades
Win Rate
Maximum Drawdown
Profit Factor
Average Trade
Largest Win
Largest Loss
Backtesting must also avoid look-ahead bias. Historical simulations should never use information that would not have been available at the simulated trading time.

Live Trading Should Be Locked

Live trading is optional.
The platform should keep it:
1
LOCKED
until the required safety checks have been completed.
The proposed flow is:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Automated tests passed
↓
Risk limits configured
↓
Kill switch tested
↓
API permissions verified
↓
Order reconciliation verified
↓
Paper trading validated
↓
User confirmation
↓
LIVE TRADING UNLOCK
The system must never implement withdrawal functionality, and exchange API keys should never have withdrawal permissions.

Monitoring the Platform

Infrastructure monitoring can be handled through CloudWatch.
Monitor:
1
2
3
4
5
6
7
CPU
Memory
Disk
Network
Application logs
Docker logs
System health
Application metrics can also be exposed through Prometheus.
Useful metrics include:
1
2
3
4
5
6
7
8
9
10
market_data_latency
opportunities_detected
opportunities_rejected
trades_executed
trade_errors
api_latency
websocket_disconnects
pnl
drawdown
risk_events
Grafana can then visualize these metrics.

Add a Health Endpoint

A simple application health endpoint can be:
1
GET /health
With a response such as:
1
2
3
4
5
6
7
{
"status": "healthy",
"mode": "paper",
"database": "healthy",
"redis": "healthy",
"market_data": "healthy"
}
Deeper health checks can also cover:
1
2
3
4
5
6
Database
Redis
Exchange connection
WebSocket
Disk
Memory

Security Checklist Before Live Trading

Before considering live trading, verify:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[ ] HTTPS enabled
[ ] SSH restricted to known IPs
[ ] Database not publicly accessible
[ ] Redis not publicly accessible
[ ] Secrets not stored in Git
[ ] Secrets not logged
[ ] Exchange withdrawal permission disabled
[ ] Authentication enabled
[ ] Authorization enabled
[ ] Rate limiting enabled
[ ] Audit logging enabled
[ ] Kill switch tested
[ ] Order reconciliation tested
[ ] Backups configured
[ ] Monitoring enabled
[ ] Alerts configured
This checklist is as important as the arbitrage logic itself.

Why the Kill Switch Matters

Imagine the exchange API begins returning incorrect information.
Without a kill switch:
1
2
3
4
5
6
7
Market data problem
↓
Bot continues
↓
Potential trades
↓
Unexpected losses
With a kill switch:
1
2
3
4
5
6
7
Market/API anomaly
↓
Risk engine
↓
SAFE STOP
↓
No new trades
The platform should prefer stopping over trading with uncertain information.

A Realistic Arbitrage Decision

Suppose the system sees:
1
2
3
4
5
Exchange A
BTC Buy = $100,000

Exchange B
BTC Sell = $100,300
The gross spread is:
1
Gross spread = 0.30%
After estimated costs:
1
2
3
4
5
Trading fees = 0.20%
Slippage = 0.05%
Other costs = 0.02%
--------------------------------
Expected net = 0.03%
If the minimum required net profit is:
1
0.10%
the system rejects the opportunity:
1
2
3
4
REJECTED

Reason:
NET PROFIT BELOW THRESHOLD
That is a feature, not a failure.

Starting With ₹100

The initial configuration can use:
1
2
3
Capital: ₹100
Maximum trade: ₹10
Maximum daily loss: ₹2
But ₹100 should be treated as a learning and experimental amount, not guaranteed income-generating capital.
There is another important consideration: exchanges may impose minimum-order requirements. That means some ₹10 trades may simply be impossible.
The application must check exchange-specific minimum order rules before attempting execution.
If the minimum is not satisfied:
1
NO TRADE

Suggested Repository Structure

The proposed repository structure is:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
bb-arbitrage/

├── backend/
│ ├── app/
│ │ ├── api/
│ │ ├── core/
│ │ ├── config/
│ │ ├── models/
│ │ ├── schemas/
│ │ ├── services/
│ │ ├── exchanges/
│ │ ├── market_data/
│ │ ├── arbitrage/
│ │ ├── risk/
│ │ ├── portfolio/
│ │ ├── paper_trading/
│ │ ├── live_trading/
│ │ ├── backtesting/
│ │ ├── accounting/
│ │ ├── notifications/
│ │ ├── monitoring/
│ │ ├── security/
│ │ └── main.py
│
│ └── tests/
│
├── frontend/
│ ├── app/
│ ├── components/
│ ├── hooks/
│ ├── lib/
│ ├── services/
│ └── types/
│
├── infra/
│ ├── docker/
│ ├── aws/
│ └── terraform/
│
├── docs/
│
├── scripts/
│
├── .github/
│ └── workflows/
│
├── docker-compose.yml
├── .env.example
├── README.md
├── ARCHITECTURE.md
└── SECURITY.md

What Could Come Next?

Once the MVP is stable, the platform can evolve with:
  • More exchanges
  • More trading pairs
  • Advanced order-book analysis
  • Better slippage models
  • Historical data pipelines
  • Strategy comparison
  • Advanced performance analytics
  • Telegram alerts
  • Mobile-responsive dashboard
  • Multi-user support
  • Role-based access
  • AWS ECS deployment
  • RDS PostgreSQL
  • ElastiCache Redis
  • Secrets Manager
  • Automated backups
  • More sophisticated anomaly detection
AI can also be added as an analysis layer, but it should never override deterministic risk controls.

What Does Success Look Like?

Success is not:
1
₹100 → ₹1,00,000
The first objective is:
1
2
3
4
5
6
7
8
9
10
11
12
13
Correct market data
↓
Correct arbitrage calculation
↓
Correct cost calculation
↓
Correct risk controls
↓
Realistic paper trading
↓
Reliable deployment
↓
Safe operation

Final Architecture

The finished platform can be visualized conceptually like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
AWS CLOUD
┌───────────────────────────────────────────────┐
│ │
│ EC2 │
│ │
│ ┌─────────┐ ┌──────────────┐ │
│ │ Nginx │─────>│ Next.js │ │
│ └────┬────┘ └──────────────┘ │
│ │ │
│ v │
│ ┌──────────────┐ │
│ │ FastAPI │ │
│ └──────┬───────┘ │
│ │ │
│ ┌─────┼───────────────┐ │
│ │ │ │ │
│ v v v │
│ Redis PostgreSQL Arbitrage Engine │
│ │ │ │ │
│ │ │ ┌────┴────┐ │
│ │ │ │ Risk │ │
│ │ │ │ Engine │ │
│ │ │ └────┬────┘ │
│ │ │ │ │
│ │ │ Paper/Live │
│ │ │ │ │
│ └─────┴───────────────┘ │
│ │
│ AWS S3 │
│ Historical Data / Reports / Backups │
│ │
│ CloudWatch │
│ Logs / Monitoring │
│ │
└───────────────────────────────────────────────┘

Conclusion

BB-Arbitrage is not designed as a shortcut to guaranteed crypto profits.
It is a serious engineering project that brings together:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Crypto Market Data
+
Arbitrage Logic
+
Risk Management
+
Paper Trading
+
Backtesting
+
Python/FastAPI
+
Next.js
+
Docker
+
AWS EC2
+
S3
+
Monitoring
+
DevOps
The most important principle is simple:
When the system is uncertain, it should not trade.
That principle should remain at the center of BB-Arbitrage as the platform grows.

Any opinions in this article are those of the individual author and may not reflect the opinions of AWS.
Enjoyed reading this content? Let the author know!

Your likes, comments, shares, and saves help creators reach more builders.

Loading recommendations

Loading article