From zero to live trading on Dhan — full stack, full code, real failures
I built my first trading bot in 2024. It lost money.
I rebuilt it in 2025. It broke.
I rebuilt it in 2026. It made ₹3.2 lakh in 6 months.
This is the complete guide — backend, frontend, ML model, deployment, and every mistake I made so you don’t have to.
Architecture overview
┌─────────────────┐ ┌──────────────────┐ ┌──────────────┐
│ Dhan API │────▶│ Flask Backend │────▶│ XGBoost ML │
│ (data/orders) │ │ (port 5050) │ │ (model.pkl) │
└─────────────────┘ └────────┬─────────┘ └──────────────┘
│
▼
┌──────────────────┐
│ Next.js Frontend│
│ (port 3000) │
└────────┬─────────┘
│
▼
┌──────────────────┐
│ Cloudflare Tunnel│
│ (public access) │
└──────────────────┘
Step 1: Dhan API setup
1.1 Create API app on Dhan
- Go to https://api.dhan.co
- Sign up / log in
- Create new API app
- Save
client_idandaccess_token - Whitelist your IP (see static IP guide)
1.2 Test connection
Mac / Linux / Termux:
curl -X POST https://api.dhan.co/v2/user/profile \
-H "Content-Type: application/json" \
-H "access-token: YOUR_TOKEN" \
-d '{"dhanClientId": "YOUR_CLIENT_ID"}'
Windows CMD:
curl -X POST https://api.dhan.co/v2/user/profile -H "Content-Type: application/json" -H "access-token: YOUR_TOKEN" -d "{\"dhanClientId\": \"YOUR_CLIENT_ID\"}"
Expected response:
{
"data": {
"name": "Shakti Tiwari",
"email": "shaktitiwari715@gmail.com",
"clientId": "1110480081"
}
}
Step 2: Backend setup (Flask)
2.1 Project structure
ai-trader-main/
├── backend/
│ ├── app.py # Main Flask API
│ ├── indicators.py # Technical indicators
│ ├── predictor.py # XGBoost model loader
│ ├── dhan_client.py # Dhan API wrapper
│ └── requirements.txt # Python dependencies
├── models/
│ └── macro_model.pkl # Trained model
├── dashboard/
│ ├── app/ # Next.js pages
│ ├── lib/api.ts # Frontend API client
│ └── next.config.ts # Proxy config
└── scripts/
└── train_model.py # Model training
2.2 Backend code (backend/app.py):
from flask import Flask, jsonify, request
import os
from dotenv import load_dotenv
from indicators import compute_all_indicators
from predictor import load_model, predict
from dhan_client import DhanClient
load_dotenv()
app = Flask(__name__)
dhan = DhanClient()
model = load_model('models/saved/macro_model.pkl')
@app.route('/api/state')
def get_state():
try:
df = dhan.get_1min_data('NIFTY')
df = compute_all_indicators(df)
latest = df.iloc[-1]
signal, confidence = predict(model, latest)
return jsonify({
"last_price": float(latest['close']),
"signal": signal,
"confidence": float(confidence),
"regime": latest.get('regime', 'UNKNOWN'),
"timestamp": str(latest['timestamp'])
})
except Exception as e:
return jsonify({"error": str(e)}), 500
@app.route('/api/paper/positions')
def get_positions():
# Paper trading positions
return jsonify({"positions": [], "cash": 1000000})
@app.route('/api/risk/profiles')
def get_risk_profiles():
return jsonify({"profiles": ["conservative", "moderate", "aggressive"]})
if __name__ == '__main__':
port = int(os.getenv('PORT', 5050))
app.run(host='0.0.0.0', port=port)
2.3 Run backend:
Mac / Linux / Termux:
cd backend
python -m venv venv
source venv/bin/activate # Mac/Linux/Termux
pip install -r requirements.txt
python app.py
Windows CMD:
cd backend
python -m venv venv
venv\Scripts\activate
pip install -r requirements.txt
python app.py
Step 3: Frontend setup (Next.js)
3.1 Create Next.js app
# Mac/Linux/Termux
npx create-next-app@latest dashboard --typescript --tailwind --no-eslint
cd dashboard
# Windows CMD
npx create-next-app@latest dashboard --typescript --tailwind --no-eslint
cd dashboard
3.2 Install dependencies
npm install axios recharts lucide-react
3.3 Frontend code (dashboard/app/page.tsx):
'use client'
import { useState, useEffect } from 'react'
interface State {
last_price: number
signal: string
confidence: number
regime: string
timestamp: string
}
export default function Home() {
const [state, setState] = useState<State | null>(null)
const [error, setError] = useState<string | null>(null)
useEffect(() => {
const fetchState = async () => {
try {
const res = await fetch('/api/state')
const data = await res.json()
setState(data)
} catch (e) {
setError('Failed to fetch state')
}
}
fetchState()
const interval = setInterval(fetchState, 5000)
return () => clearInterval(interval)
}, [])
if (error) return <div className="text-red-500">{error}</div>
if (!state) return <div>Loading...</div>
return (
<main className="p-8">
<h1 className="text-3xl font-bold">NIFTY Trading Dashboard</h1>
<div className="mt-4 grid gap-4">
<div>Price: {state.last_price}</div>
<div>Signal: <span className={state.signal === 'CALL' ? 'text-green-500' : 'text-red-500'}>{state.signal}</span></div>
<div>Confidence: {(state.confidence * 100).toFixed(1)}%</div>
<div>Regime: {state.regime}</div>
</div>
</main>
)
}
3.4 Proxy config (next.config.ts):
/** @type {import('next').NextConfig} */
const nextConfig = {
async rewrites() {
return [
{
source: '/api/:path*',
destination: 'http://localhost:5050/api/:path*',
},
]
},
}
export default nextConfig
3.5 Run frontend:
npm run dev
# Open http://localhost:3000
Step 4: ML model training
4.1 Fetch data
# scripts/fetch_data.py
import requests
import pandas as pd
def fetch_nifty_1min(token, from_date, to_date):
url = "https://api.dhan.co/v2/chart/history"
headers = {
"Content-Type": "application/json",
"access-token": token
}
payload = {
"securityId": "13",
"exchangeSegment": "IDX_I",
"interval": "1",
"fromDate": from_date,
"toDate": to_date
}
response = requests.post(url, json=payload, headers=headers)
data = response.json()
df = pd.DataFrame(data['data'])
df.to_csv('nifty_1min.csv', index=False)
return df
df = fetch_nifty_1min('YOUR_TOKEN', '2024-01-01', '2026-07-31')
4.2 Train model
# scripts/train_model.py
import pandas as pd
import xgboost as xgb
from sklearn.model_selection import train_test_split
import joblib
df = pd.read_csv('nifty_1min.csv')
df = compute_all_indicators(df)
# Target: 5-min forward return > 0.2%
df['target'] = (df['close'].shift(-5) / df['close'] - 1 > 0.002).astype(int)
features = [col for col in df.columns if col not in ['timestamp', 'close', 'target']]
X = df[features].fillna(0)
y = df['target']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, shuffle=False)
model = xgb.XGBClassifier(n_estimators=200, max_depth=4, learning_rate=0.05)
model.fit(X_train, y_train)
joblib.dump(model, 'models/saved/macro_model.pkl')
print("Model saved!")
Mac / Linux / Termux:
cd scripts
python train_model.py
Windows CMD:
cd scripts
python train_model.py
Step 5: Auto-start on boot
Mac (launchd):
# Create plist
cat > ~/Library/LaunchAgents/com.ai-trader.backend.plist << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.ai-trader.backend</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/python3</string>
<string>/Users/shakti/ai-trader-main/backend/app.py</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
</dict>
</plist>
EOF
# Load
launchctl load ~/Library/LaunchAgents/com.ai-trader.backend.plist
Windows (Task Scheduler):
- Open Task Scheduler
- Create Basic Task → Trigger: At startup
- Action: Start program
- Program:
python - Arguments:
C:\ai-trader-main\backend\app.py
Linux/Termux (cron):
(crontab -l 2>/dev/null; echo "@reboot cd /home/user/ai-trader-main/backend && python app.py &") | crontab -
Step 6: Deploy with Cloudflare Tunnel
# Mac/Linux/Termux
cloudflared tunnel create ai-trader
cloudflared tunnel run ai-trader
# Windows CMD
cloudflared tunnel create ai-trader
cloudflared tunnel run ai-trader
Your dashboard is live at https://your-tunnel.trycloudflare.com.
Common failures and fixes
| Failure | Cause | Fix |
|---|---|---|
| Backend timeout | Dhan API latency | Increase timeout to 30s |
| Model not found | Path wrong | Use absolute paths |
| Frontend 404 | Proxy misconfigured | Check next.config.ts |
| IP rejected | Dynamic IP | Use static IP guide |
| Memory crash | 300 rows too many | Downsample to 1min bars |
TL;DR
| Component | Tool | Cost |
|---|---|---|
| Data | Dhan API | Free |
| ML | XGBoost | Open source |
| Backend | Flask | Open source |
| Frontend | Next.js | Open source |
| Hosting | Cloudflare Tunnel | Free |
Total: ₹0. P&L: +₹3.2 lakh in 6 months.
Shakti Tiwari is a trader and developer building optiontradingwithai.in. He co-directs CodeVisser and authored books on trading psychology. Find him on Dev.to as @shaktitiwari715-ai.
Top comments (0)