diff --git a/docs/architecture.md b/docs/architecture.md index 2582364..e272356 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -289,55 +289,14 @@ Test seams: - **`dispatcher.test.js`** — every visibility registered via `bot.command()`, dispatcher does NOT install any `bot.on()` middleware, handler identity preserved. - **`help-command.test.js`** — module grouping, `(protected)` suffix, zero private-command leakage, HTML escaping of module names + descriptions, placeholder when no commands are visible. - **`escape-html.test.js`** — the four HTML entities, non-double-escaping, non-string coercion. -- **`trading/symbols.test.js`** — registry size, case-insensitive lookup, currency set, grouped listing. -- **`trading/format.test.js`** — VND dot-separator, USD comma-separator, crypto trailing-zero stripping, stock flooring, P&L formatting. -- **`trading/portfolio.test.js`** — empty portfolio, KV round-trip, migration-safe load, add/deduct currency and assets, insufficient balance rejection. -- **`trading/handlers.test.js`** — all 5 commands: topup/buy/sell/convert/stats with mocked price APIs, input validation, edge cases. + +Each module adds its own tests under `tests/modules//`. See module READMEs for coverage details. Tests inject fakes (`fake-kv-namespace`, `fake-bot`, `fake-modules`) via parameter passing — no `vi.mock`, no path-resolution flakiness. -## 13. The trading module +## 13. Module-specific documentation -A paper-trading system where each Telegram user manages a virtual portfolio. Five public commands: - -| Command | Action | -|---------|--------| -| `/trade_topup [currency]` | Add fiat (VND default). Tracks cumulative invested via `totalvnd`. | -| `/trade_buy ` | Buy at market price, deducting VND. Stocks must be integer quantities. | -| `/trade_sell ` | Sell holdings back to VND at market price. | -| `/trade_convert ` | Convert between fiat currencies (VND, USD). | -| `/trade_stats` | Portfolio breakdown with all assets valued in VND, plus P&L vs invested. | - -### Data model - -Per-user portfolio stored as a single KV object at key `user:`: - -```js -{ currency: { VND, USD }, stock: {}, crypto: {}, others: {}, totalvnd: 0 } -``` - -### Price sources - -Three free APIs fetched in parallel, cached in KV for 60 seconds: - -- **CoinGecko** — crypto (BTC, ETH, SOL) + gold (PAX Gold as proxy), priced in VND. -- **TCBS** — Vietnam stock market (TCB, VPB, FPT, VNM, HPG), close price × 1000. -- **open.er-api.com** — forex (USD/VND rate). - -On partial API failure, available data is returned; on total failure, stale cache up to 5 minutes old is used before surfacing an error. - -### File layout - -``` -src/modules/trading/ -├── index.js — module entry, wires handlers to commands -├── symbols.js — hardcoded symbol registry (9 assets, 2 currencies) -├── format.js — VND/USD/crypto/stock/P&L formatters -├── portfolio.js — per-user KV read/write, balance checks -├── prices.js — API fetching + 60s cache -├── handlers.js — topup/buy/sell/convert handlers -└── stats-handler.js — stats/P&L breakdown handler -``` +Each module maintains its own `README.md` with commands, data model, and implementation details. See `src/modules//README.md` for module-specific docs. ## 14. Non-goals (for now) diff --git a/docs/codebase-summary.md b/docs/codebase-summary.md index 42afd72..bdbee7c 100644 --- a/docs/codebase-summary.md +++ b/docs/codebase-summary.md @@ -35,14 +35,6 @@ Telegram update → POST /webhook → grammY secret validation → ctx.reply() → response to Telegram ``` -### Trading Module Price Fetch -``` -User sends /trade_buy → handler calls getPrice(db, symbol) -→ getPrices(db) checks KV cache (key: "prices:latest") -→ if stale (>60s): fetch CoinGecko + TCBS + ER-API in parallel -→ merge results, cache in KV → return price in VND -``` - ### Deploy Pipeline ``` npm run deploy → wrangler deploy (upload to CF) @@ -59,13 +51,9 @@ npm run deploy → wrangler deploy (upload to CF) | `vitest` | Test runner (dev) | ^2.1.0 | | `wrangler` | Cloudflare Workers CLI (dev) | ^3.90.0 | -## External APIs (Trading Module) +## Module Documentation -| API | Purpose | Auth | Rate Limit | -|-----|---------|------|-----------| -| CoinGecko `/api/v3/simple/price` | Crypto + gold prices in VND | None | 30 calls/min (free) | -| TCBS `/stock-insight/v1/stock/bars-long-term` | Vietnam stock close prices | None | Unofficial | -| open.er-api.com `/v6/latest/USD` | USD/VND forex rate | None | 1,500/month (free) | +Each module maintains its own `README.md` with commands, data model, and implementation details. See `src/modules//README.md`. ## Test Coverage diff --git a/src/modules/trading/README.md b/src/modules/trading/README.md new file mode 100644 index 0000000..fffb6bf --- /dev/null +++ b/src/modules/trading/README.md @@ -0,0 +1,75 @@ +# Trading Module + +Paper-trading system where each Telegram user manages a virtual portfolio. + +## Commands + +| Command | Action | +|---------|--------| +| `/trade_topup [currency]` | Add fiat (VND default). Tracks cumulative invested via `totalvnd`. | +| `/trade_buy ` | Buy at market price, deducting VND. Stocks must be integer quantities. | +| `/trade_sell ` | Sell holdings back to VND at market price. | +| `/trade_convert ` | Convert between fiat currencies (VND, USD). | +| `/trade_stats` | Portfolio breakdown with all assets valued in VND, plus P&L vs invested. | + +## Supported Symbols + +| Symbol | Category | Source | Label | +|--------|----------|--------|-------| +| BTC | crypto | CoinGecko | Bitcoin | +| ETH | crypto | CoinGecko | Ethereum | +| SOL | crypto | CoinGecko | Solana | +| TCB | stock | TCBS | Techcombank | +| VPB | stock | TCBS | VPBank | +| FPT | stock | TCBS | FPT Corp | +| VNM | stock | TCBS | Vinamilk | +| HPG | stock | TCBS | Hoa Phat | +| GOLD | others | CoinGecko (PAX Gold) | Gold (troy oz) | + +Currencies: VND, USD. + +## Data Model + +Per-user portfolio stored as a single KV object at key `user:`: + +```js +{ currency: { VND, USD }, stock: {}, crypto: {}, others: {}, totalvnd: 0 } +``` + +- `totalvnd` tracks cumulative VND value of all top-ups (cost basis for P&L) +- VND is the sole settlement currency — buy/sell deducts/adds VND + +## Price Sources + +Three free APIs fetched in parallel, cached in KV for 60 seconds: + +| API | Purpose | Auth | Rate Limit | +|-----|---------|------|-----------| +| CoinGecko `/api/v3/simple/price` | Crypto + gold prices in VND | None | 30 calls/min (free) | +| TCBS `/stock-insight/v1/stock/bars-long-term` | Vietnam stock close prices (× 1000) | None | Unofficial | +| open.er-api.com `/v6/latest/USD` | USD/VND forex rate | None | 1,500/month (free) | + +On partial API failure, available data is returned. On total failure, stale cache up to 5 minutes old is used before surfacing an error. + +## File Layout + +``` +src/modules/trading/ +├── index.js — module entry, wires handlers to commands +├── symbols.js — hardcoded symbol registry (9 assets, 2 currencies) +├── format.js — VND/USD/crypto/stock/P&L formatters +├── portfolio.js — per-user KV read/write, balance checks +├── prices.js — API fetching + 60s cache +├── handlers.js — topup/buy/sell/convert handlers +└── stats-handler.js — stats/P&L breakdown handler +``` + +## Adding a Symbol + +Add one line to `symbols.js`: + +```js +NEWSYM: { category: "crypto", apiId: "coingecko-id", label: "New Coin" }, +``` + +For stocks, `apiId` is the TCBS ticker. For crypto/gold, `apiId` is the CoinGecko ID.