FastAPI-based backend that receives TradingView strategy alerts, validates them, applies risk checks, and then routes them to paper trading or Kotak Neo live execution. Phase 1 is intentionally backend-only and defaults to paper mode for safety.
- TradingView webhook endpoint at
POST /webhook/tradingview - Secret validation, symbol allow-listing, action checks, quantity checks, and duplicate alert protection
- Risk engine with daily trade limits, daily loss limit, open-position limit, and trading window enforcement
- Paper trading mode with simulated order IDs and local position tracking
- Live trading safety gate that requires both
TRADING_MODE=liveandENABLE_LIVE_ORDERS=true - Broker-source-of-truth position reconciliation every 10 seconds in live mode
- Order/trade state machine with
PENDING,PLACED,PARTIAL,FILLED,CLOSED, andREJECTED - Startup recovery that rebuilds local trade state from broker positions after restart
- Broker heartbeat monitoring, global circuit breaker, exponential-backoff retries, and slippage protection
- Best-effort Kotak order-feed websocket support with polling fallback
- Kotak Neo auth and order service wrappers using the official Python SDK
- SQLite by default, with SQLAlchemy models that can be moved to PostgreSQL later
- Structured JSON logging
- Docker and docker-compose support
- Basic pytest coverage for webhook and risk behaviour
- Default mode is
paper. Keep it that way until you have verified the full alert flow end to end. - Live trading is blocked unless both
TRADING_MODE=liveandENABLE_LIVE_ORDERS=true. - Broker positions are treated as the source of truth in live mode. Local database state is reconciled to the broker, not the other way around.
- If startup reconciliation fails, the API can still start, but the global circuit breaker keeps live orders blocked until broker connectivity recovers.
- As of
2026-05-15, the currently published Kotak Neo v2 flow uses an app/web dashboard token plus TOTP, MPIN, andUCC. Older access-token/consumer-secret login flows are deprecated. - This project stores and executes alerts exactly as received. You should test thoroughly on a disposable setup before routing real capital.
- Commodity lot sizes, symbol names, and product selection must match your Kotak account permissions and current exchange contracts.
tradingview-kotak-bot/
app/
main.py
config.py
models.py
database.py
schemas.py
routes/
webhook.py
health.py
trades.py
services/
circuit_breaker.py
kotak_auth.py
kotak_orders.py
reconciliation.py
retry.py
risk_engine.py
signal_parser.py
state_machine.py
trade_logger.py
duplicate_guard.py
utils/
logging.py
time_utils.py
tests/
.env.example
requirements.txt
Dockerfile
docker-compose.yml
README.md
- Create and activate a Python 3.11+ virtual environment.
- Install dependencies:
pip install -r requirements.txt- Copy the environment file:
cp .env.example .env- Edit
.envand set at least:
WEBHOOK_SECRET=your-long-random-secret
TRADING_MODE=paper
ENABLE_LIVE_ORDERS=false
ALLOWED_SYMBOLS=SILVERMIC
DATABASE_URL=sqlite:///./trades.db
RECONCILIATION_POLL_INTERVAL_SECONDS=10
MAX_SLIPPAGE_PCT=0.5- Start the API:
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000- Verify health:
curl http://127.0.0.1:8000/health- Create
.envfrom.env.example. - Start the stack:
docker-compose up --build- The API will be available at
http://127.0.0.1:8000.
- Open your TradingView strategy alert.
- Enable webhook URL.
- Set the webhook URL to:
https://your-public-url/webhook/tradingview
- Use JSON in the alert message body.
Sample TradingView alert JSON:
{
"secret": "MY_SECRET_KEY",
"strategy": "MACD_SILVER_MICRO",
"symbol": "SILVERMIC",
"exchange": "MCX",
"action": "BUY",
"quantity": 1,
"price": "{{close}}",
"time": "{{time}}",
"alert_id": "{{strategy.order.id}}"
}Supported actions:
BUYSELLEXIT
- Install ngrok and authenticate it with your account.
- Run your API locally on port
8000. - Start ngrok:
ngrok http 8000- Copy the HTTPS forwarding URL from ngrok and append
/webhook/tradingview. - Paste that URL into your TradingView alert webhook configuration.
Example:
https://abcd-1234.ngrok-free.app/webhook/tradingview
GET /healthPOST /webhook/tradingviewGET /signalsGET /ordersGET /tradesGET /positionsPOST /positions/exit
GET /health now also exposes broker heartbeat state, circuit breaker state, startup recovery status, and the latest reconciliation timestamp.
curl -X POST http://127.0.0.1:8000/webhook/tradingview \
-H "Content-Type: application/json" \
-d '{
"secret": "your-long-random-secret",
"strategy": "MACD_SILVER_MICRO",
"symbol": "SILVERMIC",
"exchange": "MCX",
"action": "BUY",
"quantity": 1,
"price": 101250.0,
"time": "2026-05-15T10:15:00+05:30",
"alert_id": "manual-buy-001"
}'Paper mode is the default and safest place to start.
- Orders are not sent to Kotak Neo.
- A synthetic broker order ID like
PAPER-20260515101500-ab12cd34is generated. - Paper entry orders are marked
FILLEDimmediately so the same order/trade state machine can be exercised before going live. - Signals, orders, and local position state are still written to the database.
GET /positionsreturns positions derived from open paper trades.
Recommended paper-mode checklist:
- Send a
BUYalert and confirm it appears in/signals,/orders,/trades, and/positions. - Send the same
alert_idagain and confirm it is rejected. - Send an
EXITalert or callPOST /positions/exitand confirm the position closes.
Do not switch to live mode until paper mode has been fully validated.
- Keep
TRADING_MODE=paperwhile validating TradingView alert formatting. - Fill live credentials in
.env. - Add your current Kotak
UCCbecause the present v2 flow requires it. - Confirm your symbol naming and product configuration with your Kotak account.
- Switch both flags:
TRADING_MODE=live
ENABLE_LIVE_ORDERS=true- Restart the API.
- Send one controlled low-risk alert first and review logs plus
/orders.
Recommended live-mode safeguards to keep enabled:
RECONCILIATION_POLL_INTERVAL_SECONDS=10ENABLE_ORDER_FEED_WEBSOCKET=trueENFORCE_SLIPPAGE_PROTECTION=trueMAX_SLIPPAGE_PCT=0.5BROKER_HEARTBEAT_FAILURE_THRESHOLD=3
Current live-related notes:
KOTAK_CONSUMER_KEYshould be the token generated from the Kotak Neo app/web Trade API dashboard.KOTAK_TOTP_SECRET,KOTAK_MPIN,KOTAK_MOBILE_NUMBER, andKOTAK_UCCare required for the current SDK-backed login path.KOTAK_CONSUMER_SECRETandKOTAK_PASSWORDremain in.env.exampleas placeholders because older setups used them, but the current v2 flow does not rely on them.- The code now attempts to use Kotak's official
subscribe_to_orderfeed()support when available in the SDK, and falls back to polling order/position state when websocket streaming is unavailable or unstable. - Quote-field and search-token parsing for slippage protection include guarded TODO comments where exact response keys should be confirmed against your Kotak contract documentation.
signalsorderstradesrisk_eventsbroker_sessions
The SQLAlchemy setup is database-URL driven, so moving to PostgreSQL later is primarily a configuration and migration exercise.
- Live orders are created locally as
PENDING, then move through broker reconciliation toPLACED,PARTIAL,FILLED,CLOSED, orREJECTED. - Broker positions are polled every 10 seconds and used as the live source of truth for
/positionsand restart recovery. - If the broker reports an open position with no matching local trade, the system creates a recovered orphan trade and marks it accordingly.
- If local state shows duplicate live trades for the same symbol after restart, the circuit breaker opens and blocks new live execution.
Logs are emitted as structured JSON and include:
- Incoming alerts
- Validation and risk rejections
- Paper order simulations
- Broker errors
- Successful order execution events
pytestThis code uses the official Kotak Neo Python SDK wrapper for live flows. The live implementation is intentionally isolated in:
If Kotak changes the SDK response structure, you will likely only need to adjust the order-id extraction or the login metadata handling inside those two files.