Hold the line. · A RawData product
Drawline is a trading discipline platform. You design your own prop-firm-style challenge (starting capital, profit target, fail line, risk per trade, minimum reward-to-risk, allowed assets, your own conditions) and trade it on your real exchange account. Drawline imports every trade through read-only API keys, checks it against your rules, journals it, and scores you on whether you followed your plan as well as on your results.
The name comes from the line every challenge has that you don't cross: the drawdown limit, the fail threshold, the rules you committed to before the trade. It's also a line drawn on a chart.
- Plan locked
- Foundation
- Rule engine + journal
- Kraken import + first 30-day review
- Charts
- Admin panel + hosting + challenge credits
- Pro Mode
- Later: forum, public Integrity Score, Coinbase
- Read-only. Drawline never places orders and never holds money. It refuses exchange keys that can trade or withdraw.
- No signals, no advice. It measures discipline and never tells anyone what to trade.
- Honest by design. It's an educational tool. Most checks run on what you record in the journal, and the exchange supplies the facts: facts from the exchange, intent from the journal.
- Scores measure discipline, never profit. The Integrity Score rewards following your plan. There are no P&L leaderboards.
- Rules are judged on the server. Rules lock when a challenge starts, so nobody can move the line afterwards.
- The fee buys access, never an outcome. Passing, failing and quitting a challenge all cost exactly the same.
- Not a charting clone. Charts support the plan and the journal. They aren't the product.
The RawData Ladder takes a small account from $100 to $1,000 in levels, with fixed risk, loss floors, and payouts. v1 is done when Ladder Level 1 runs end to end in the app: every trade imported, every rule checked, and a 30-day review scorecard generated.
Milestone 1: Foundation (done)
- ✅ Monorepo, tooling, PostgreSQL, health check
- ✅ Accounts database, roles and permissions (staff actions go to an append-only audit log)
- ✅ Log in / log out, sessions, password reset with breached-password check
- ✅ Two-factor authentication (authenticator app + recovery codes)
- ✅ First screens in the approved design, with the RawData footer
- ✅ Sign up (18+), email verification, forgot password, with a dev-only inbox for testing emails
- ✅ Login page with a rotating quote
- ✅ Settings: see where you're signed in and sign devices out, change your password, move 2FA to a new phone (or turn it off; staff can't)
Milestone 2: Rule engine + journal (in progress)
- ✅ The engine core: rules as reusable blocks, risk bands that step up with your equity, and a rule that can't run says so instead of guessing
- ✅ Position-size calculator: type an entry, stop and target, and see the size, the reward-to-risk after fees, and which of your rules it breaks
- ✅ Build a challenge from the Ladder template, review the rules in plain language, and start it — which locks them for good. The database itself refuses to unlock them afterwards
- ✅ Your challenge at a glance: equity, your floor (which climbs as you grow, and never falls back), your target, and how many full-risk losses in a row would reach the floor
- ✅ The calculator now checks the rules your challenge locked in, not a set of defaults
- ✅ A clock on your challenge: the day you are on, counted in your own timezone, and the time since you started. It counts up, not down — the Ladder has no deadline, and a countdown is just pressure to trade. Set a time limit yourself and it counts that down too
- ✅ What you're allowed to trade: your challenge's directions and assets, and whether an order may be bigger than the cash you have. Borrowing is worked out from the size of the order, not from a box you tick, so there is nothing to get wrong
- 🔄 Trade plans: a plan you save is a draft, and it stays live — its numbers are worked out fresh every time you open it. Locking it is you saying "I'm taking this trade now", and from that moment nothing about it can change. The table and the rules behind it are built; the screen is next
- ⬜ The rest of the 12 Ladder rules
- ⬜ The journal
- ⬜ Lockouts and the Integrity Score
- The plan screen: save a plan, own up to any rule it breaks, and lock it before you enter
- Your trades and the journal that reviews them, which is what the rest of the Ladder rules need in order to check anything
- Lockouts, the "can I trade right now?" banner, and the Integrity Score
TypeScript everywhere · React + Vite + Tailwind · Fastify (Node.js 24) · PostgreSQL + Drizzle · Vitest
Features
- Rule block R2
instrument_policy: which directions and assets a challenge allows, and whether an order may be bigger than the cash available. Leverage is measured from the order size rather than declared, so the rule can't be dodged by leaving a field blank - The Ladder template now ships R2: long only, cash only, borrowing unlocking at 1.5x the stake with 20 closed trades at 90% adherence, then 2x on BTC/ETH/SOL/XRP. The unlock roster restricts borrowing, not buying
Technical Improvements
- Migration
0004_plans: thetrade_planstable, with triggers that refuse any change to a locked plan and refuse a locked plan without its sizing and verdicts. The plan lock is enforced below the service, like challenge activation NotEvaluablecarries areason(missing_plan_fieldormissing_data), surfaced on the rule result and over the API, so a rule the trader can fix is told apart from one Drawline simply can't run yetRuleBlockgainedacknowledgeable: whether a plan may knowingly break that rule up front. True on the trade-open blocks, false on the floor, the target and the time limit
Docs
API.md→ Plans rewritten as the save/lock contract, written before the routes: draft and locked plans, acknowledged breaks that must match the verdict shown,PLAN_INCOMPLETEagainst a storednot_evaluable, the statuses and the error codes. Fixed orphaned table rows left in the section by Session #8DATABASE_SCHEMA.md→trade_plansbrought in line with the contract (noteandcheckscolumns, the draft/locked split, the acknowledgment shape)- CLAUDE.md guidelines 42 (a draft is recomputed, a locked plan is frozen) and 43 (leverage is measured, never declared)
Features
- A clock on the challenge: "Day N" counted on the wall calendar in the challenge's own timezone, a ticking elapsed counter, and the start time. Days remaining appear only when the challenge has a time limit
- Rule block
time_limit: an optional deadline,not_evaluablebefore activation, promoted tofailby severity. Not part of the Ladder template, which has no deadline by design
Technical Improvements
packages/shared/src/time.ts: civil-date helpers (civilDateIn,civilDayNumber,civilDaysBetween) that count calendar days in an IANA zone, so a 23 or 25 hour day still counts as one day.isValidTimeZonemoved here fromaccounts.tspackages/rules/src/clock.ts:dayNumberOfandchallengeClock, pure like the rest of the engineChallengeStategainedstartedAtandtimezone, which the circuit breakers and blackout windows will both needtoChallengeResponsenow takesnow, and the challenge response carries aclockblock withserverNowso the page ticks on the server's clock rather than the browser's- The create-challenge request validates its timezone against
Intlinstead of accepting any string - 180 tests (159 before)
Docs
rdsync/docs/DEPLOYMENT.md(new): going live on the OVH box in stages A to G, the backup chain with commands, the three-credential model, the restore procedure, the key inventory, and what we deliberately don't do. CLAUDE.md's go-live checkboxes condensed to point at it- Backups reordered so the whole chain exists before the first account on the box, and the freshness alert moved to the home side, where it still fires when the box is dead
- CURRENT_STATE said check-in 6 was awaiting the owner's walkthrough; the Session #8 notes recorded it as passed
Features
- Challenge from the RawData Ladder template:
GET /challenges/current,POST /challenges,POST /challenges/:id/activate, with activation locking the rule set for good - Challenge page: equity, floor (with the ratchet), target, "losses to floor", the rules in plain language, and a two-step activation
- Rule blocks
equity_floor(base floor + ratchet steps that never lower) andprofit_target(reports the newmetoutcome) lossesToFloor: full-risk losses to the floor, compounded and band-aware (7 at $100 with a $70 floor, not the 6 simple division gives)
Enhancements
POST /plans/previewnow runs the caller's active challenge's locked rules; equity no longer crosses the wire, and no challenge returns409 NO_ACTIVE_CHALLENGE- Severity promotion moved into
evaluate(): a block reports what happened, andseverity: 'fail'turns a violation into a challenge-endingfailin one place - Plan page reads its equity and rules from the challenge; the Equity field is gone
Technical
- Migration
0003_challenges(rule_sets,rule_set_versions,challenges) with four triggers enforcing the lock below the service, and a partial unique index for one active challenge per user ChallengeState.peakEquity(drives the floor ratchet) and themetrule outcomemoney()column helper (NUMERIC(28,10)) in the Drizzle schema- 159 tests (127 before);
npm run checkclean
Docs
- Monetization decided and recorded: challenge starts as credits, packs on cards and single starts in USDC, no escrow (deferred revenue instead), cohorts in v2. Brief → Monetization, DATABASE_SCHEMA → Billing & Credits, API.md → Billing & Credits
- Hard guardrail 6 ("fees buy access, never an outcome") and implementation guidelines 34–39
- The activity floor for rankings decided: no volume quota, a full 20-trade window, cohort-scoped, with
trade_scores.risk_fractionstored from day one - API.md marks the challenge routes and the rewritten plan preview as built; CODE_MAP, CURRENT_STATE and README updated
On the source. This page mirrors a private repository. The milestones, changelog and narrative come from the project's own README and CHANGELOG, and the statistics are read live from the GitHub API, so it reflects the state of the work rather than a summary written after the fact. No source code is published here.