尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证制作者的介绍仅有上面的一句话。 更多详情请阅读仓库 README。 仓库 README ↗
正在加载完整 README。
查看完整 README ↗Build a swing trading entry rule, backtest it honestly, and compare exit strategies on identical entries. A $0/month portfolio project, built in about ten days by directing AI coding agents.
Live demo · 52/52 acceptance criteria green · no sign up
Not investment advice. The public demo runs on a generated market, not real prices, and the generated market has a planted edge, so any strategy will look good on it. Nothing here is a recommendation to buy or sell anything.
🎬 Demo GIF pending. Until then, the live demo is the real thing and the demo script below is the two minute tour.
Most backtesting tools let you tune an entry rule until the equity curve looks good, which is how you end up with a strategy that fits the past and nothing else. This one is built around three things that make it harder to fool yourself:
Plus the boring honesty: expectancy per bar held next to plain expectancy, MAE and MFE guides from in sample winners only, distinct entry weeks as the real sample size rather than trade count, and an assumptions header on every result stating the fill model, slippage and cooldown.
rsi(14) < 75, and watch the URL and the JSON panel update as you type.DEMO-INDEX with the in sample and out of sample split marked, and the trade list filtered to
exit_reason = delisted.flowchart LR
subgraph Presentation
W["apps/web<br/>Next.js, static export<br/>Vercel"]
A["services/api<br/>FastAPI, ~320 lines<br/>Lambda container"]
end
subgraph Application
U["engine.api<br/>scan, backtest"]
end
subgraph Domain
D["engine/<br/>indicators · rules · exits<br/>sim · baseline · metrics"]
end
subgraph Infrastructure
I["engine/data, engine/synthetic<br/>engine/live<br/>Parquet, Alpaca"]
end
W -->|"typed OpenAPI client"| A
A --> U
U --> D
U --> I
I --> D
Every arrow points inward, and nothing points back out: the domain knows nothing about the API, the web app, Parquet or Alpaca.
Clean Architecture, with the dependency rule enforced by a test rather than a convention:
engine/tests/test_engine_boundary.py fails the build if
the domain imports FastAPI, Starlette or uvicorn. The API is ~320 lines because every decision
lives inward of it; routers assemble responses and nothing else.
Exit precedence lives in exactly one function, step(position, bar), and "never special case an
exit outside it" is an enforced invariant. Both the portfolio day loop and the per trade exit lab
loop call it, so the two modes cannot disagree about what an exit does.
Read more: spec 0001 (stack) · all 10 specs · ADR digest, 17 decisions tracked to outcomes · agent log: how it was built
| Why | ||
|---|---|---|
| TypeScript (strict) on Node 24, Next.js App Router | static export | No server needed, so Vercel Hobby hosts it free |
| Tailwind + shadcn/ui, TanStack Query/Table, Lightweight Charts | Tables and charts are most of the UI | |
| Python 3.12 (uv), FastAPI + Pydantic v2 | Lambda container, ap-southeast-1 | Pydantic models are the contract, and generate the TypeScript client |
| Polars (indicators and rules), NumPy and plain Python loops (simulator) | Deliberately not Numba or vectorbt. Profiling decided this, not taste — see ADR-006 and 016 | |
| No database, no auth, no background jobs | 10 to 20 MB of Parquet ships inside the image. State lives in the URL | |
pnpm + uv monorepo, one Makefile | make ci runs everything CI runs |
Things it deliberately does not have: accounts, saved rules, alerts, watchlists, OR groups in rules, intraday data, fundamentals, short selling, parameter sweeps, walk forward, Monte Carlo, or hosted real data. Those are listed as non goals, not oversights.
| Piece | How it is free |
|---|---|
| Web app | Vercel Hobby, static export, deployed from Git |
| API | AWS Lambda always free tier. 2,048 MB, 30 s timeout, x86_64, one container image |
| Image registry | ECR, images tagged with the commit SHA |
| Data | No database. Synthetic Parquet is built into the image |
| CI/CD | GitHub Actions, free on a public repo. Deploys use OIDC, so no AWS keys are stored |
| Staying awake | One /api/v1/health call a week, so the image does not go Inactive and spoil the first visit after a quiet spell. Not a warm up ping — the web app does that itself on page load |
| Guard rails | A $1 budget alarm and a throttle alarm, both by email |
Measured cold start for a visitor hitting an idle function: 2.66 s (warm: 0.07 s). The first
call right after a deploy is slower and different, 9 to 14 s, because Lambda optimises each new
image once; infra/README.md §6 keeps the two numbers apart so neither gets quoted as the other.
All of these point the same way: results look better than reality.
Therefore every finding here is a hypothesis. Confidence would need delisted inclusive data, walk forward testing, and a paper traded forward test. The research note states its own confidence level and names which of these limits bite it.
data/live/ on one machine and never published. The API
refuses to start in live mode anywhere but 127.0.0.1, and refuses on Lambda or in CI whatever
the binding says.research/ folder; only synthetic notes are
published.data/ and research/ are gitignored.make setup # install from lockfiles (pnpm --frozen-lockfile, uv sync --frozen)
make hooks # once per clone: install the pre-commit hooks
make data # generate the seed 42 synthetic market into data/synthetic (gitignored)
make dev # API on 127.0.0.1:8000 + web on :3000
make ci # every check CI runs, in one command
Live mode, local only, needs Alpaca keys in your environment or a local .env:
make load-live # Alpaca daily bars into data/live (gitignored)
make dev-live # the same app against your live data, on 127.0.0.1 only
| Suite | What it is |
|---|---|
26 oracle tests (tests/oracle/) | Owner written correctness tests, protected by a pre commit guard and a CI label so no agent can edit them. They define correct behaviour for every exit type, loop parity, look ahead and MAE/MFE, and they were written before the engine |
141 acceptance tests (tests/acceptance/) | Written from the criteria and contracts only. All 52 MUST criteria are required and green; test_traceability.py fails the build if the gate and the traceability matrix disagree |
| 710 Python tests, ~450 web tests | Unit tests beside their packages, plus Vitest for the UI |
Golden references (tests/golden/) | Naive loop implementations that the fast paths are checked against |
make test · make test-acceptance · make test-oracle · make lint · make typecheck
The GIF above is the one artifact that needs a human. Record the six steps of the demo script
against make dev on the seed 42 market, at 375 px wide (every page is checked to work there), and
save it to docs/assets/demo.gif. Keep it under about 10 MB so it loads on this page, and make
sure the synthetic banner is legible in the first frame — it is the first thing the GIF has to say.
A learning and portfolio project with one real user, never sold. Why there is no monetisation.