SKIP TO CONTENT
← ANISH SHEJAWALECASE STUDY 01 / SELECTED WORK
FLAGSHIP / LIVE IN PRODUCTION

PROPVEXIS

RISK MANAGEMENT FOR FUNDED TRADERS2025 —

Real-time drawdown tracking that tells a trader where they stand right now, not what happened yesterday.

01 / THE PROBLEM01 — 06
ONE SHOT

Traders on funded prop accounts get one shot at a strict rule set — breach the daily or maximum drawdown and the account is gone. Most of them track it in spreadsheets that tell them what happened yesterday, not that they are 0.4% away from losing the account right now.

02 / HOW IT FITS TOGETHERDATA PATH
FIG. 01 — CLOSED TRADE FROM TERMINAL TO SCREENWRITE PATH / IDEMPOTENT
MT5 AGENTINGEST APIPOSTGRESQLSTATS CACHERULE ENGINEBROWSERMQL5Fastify · idempotentCTEs · composite idxin-process · LRU + TTLdrawdown · targetsSocket.IO

A closed trade leaves MetaTrader 5 and is on the trader's screen in under a second. Every hop is idempotent, so nothing double-counts on retry.

03 / WHAT IT DOES04 FEATURES
01

Real-time ingestion end to end

An MQL5 Expert Advisor inside the trader's MetaTrader 5 terminal posts closed trades to a Fastify endpoint over HTTPS with a per-account token. The write is an upsert keyed on (account, MT5 ticket), so an EA that retries or reconnects mid-batch cannot double-count a fill. The trade lands in PostgreSQL and Socket.IO pushes it into that user's room — there is no polling anywhere in the path, so an open dashboard moves as positions close.

02

A configurable rule engine

Every prop firm writes its rules differently: daily drawdown measured from balance or from equity, maximum drawdown static or trailing, profit targets and minimum trading days. Each firm's rule set is stored as data and evaluated against the account after every trade, so the engine reports distance to breach rather than a verdict after the fact.

03

Analytics moved into the database

Equity curves, strike rate, expectancy, profit factor, R-distribution, MFE efficiency and breakdowns by setup, session, instrument and period are computed in PostgreSQL — one CTE query per request over composite indexes, with win/loss streaks done as gap-and-islands. SQL does only COUNT, SUM and GROUP BY; every derived number stays in JavaScript, so a mistake in the SQL surfaces as a count mismatch rather than a quietly different formula.

04

Multi-tenancy and billing

Every query is scoped by user id, with Google OAuth and email sessions issued as JWTs in httpOnly Secure cookies. Free, Pro and Premium tiers gate account limits and history depth on Razorpay recurring subscriptions, whose webhooks are signature-verified with a timing-safe HMAC over the exact raw request bytes.

04 / TRADE-OFFS06 DECISIONS

WHAT I CHOSE, AND WHAT IT COST.

Six decisions where the alternative was reasonable and I picked the other one. Each of these is a constraint the system now lives with.

01 / DELIVERY

Idempotent ingest, not at-most-once delivery

The agent retries whenever the network drops, which means the same trade can arrive several times. Deduplicating on (account, MT5 ticket) at write time makes replays harmless, at the cost of a uniqueness constraint the ingest path has to honour and a slightly heavier write.

02 / RULES

Rule sets as data, not code

Encoding each firm's rules in application logic would have been faster to write and impossible to maintain past the third firm. Storing them as data means onboarding a firm is a row rather than a release, and it means the engine has to validate configurations it has never seen.

03 / AGGREGATION

Aggregation in PostgreSQL, not in Node

Pulling rows into the application and reducing them there is easier to read and gets slow as history grows. Keeping the work in SQL trades that readability for stable latency, and puts the burden on indexes and query plans that have to be maintained deliberately.

04 / CACHING

Invalidation over short TTLs

A short expiry would have been simpler, but a trader cannot be shown a drawdown figure that is thirty seconds stale. Cached reads are invalidated by the write that changes them, which means every write path has to know what it affects.

05 / SESSIONS

httpOnly cookies over localStorage tokens

Tokens in localStorage are convenient for the client and readable by any script that gets onto the page. Cookies the browser will not hand to JavaScript remove that class of theft, and in exchange require CSRF protection and explicit cross-origin handling.

06 / TENANCY

Row-level tenant scoping over schema-per-tenant

A schema per tenant isolates data firmly and turns every migration into an operation across N schemas. Scoping by tenant id on the row keeps migrations single and moves the burden onto query discipline: no read path is allowed to omit the scope.

05 / PIPELINE05 STAGES / GITHUB ACTIONS
TESTnode:test suiteBUILDfrontend bundleSHIPrsync to EC2MIGRATEschema forwardRELEASEpm2 restart
06 / INFRASTRUCTURE03 ENVIRONMENTS

GitHub Actions deploys on merge to main — test-gated, then build, rsync to EC2, auto-migrate, pm2 reload — across three isolated environments on a single t3.micro in ap-south-1. Caddy terminates TLS automatically and reverse-proxies the API and the WebSocket. Secrets load from SSM Parameter Store through the instance IAM role and fail closed if SSM is unreachable, so no static AWS keys and no secret values sit on disk. Nightly pg_dump to S3 under a least-privilege instance role with 90-day lifecycle expiry, restores verified with pg_restore. Sentry on both ends, Prometheus and Grafana for RED metrics and connection-pool saturation, and a Route53 health check into CloudWatch and SNS that catches an outage in about 90 seconds.

RUNTIME
HOSTAWS EC2
ENVIRONMENTS03
SECRETSSSM
OBSERVABILITYGRAFANA · SENTRY
BACKUPSNIGHTLY / S3
07 / WHAT'S NEXT03 ITEMS
01
Move PostgreSQL off the application box
02
Provision Redis and run more than one worker
03
Finish the connector layer and scale the sync fleet