mirror of
https://github.com/tiennm99/miti99bot.git
synced 2026-04-17 13:21:31 +00:00
Paper trading system with 5 commands (trade_topup, trade_buy, trade_sell, trade_convert, trade_stats). Supports VN stocks via TCBS, crypto via CoinGecko, forex via ER-API, and gold via PAX Gold proxy. Per-user portfolio stored in KV with 60s price caching. 54 new tests.
4.7 KiB
4.7 KiB
phase, title, status, priority, effort, depends_on
| phase | title | status | priority | effort | depends_on | |||
|---|---|---|---|---|---|---|---|---|
| 4 | Command Handlers + Module Entry | Pending | P2 | 1.5h |
|
Phase 4: Command Handlers + Module Entry
Context
- Module pattern — reference for
init, command shape - Registry types —
BotModuletypedef - Phases 1-3 provide: symbols, prices, portfolio, format
Overview
Thin index.js wiring five trade_* commands. Each handler: parse args -> validate -> call data layer -> format reply.
File: src/modules/trading/index.js
Module shape
const tradingModule = {
name: "trading",
init: async ({ db: store }) => { db = store; },
commands: [
{ name: "trade_topup", visibility: "public", description: "...", handler: handleTopup },
{ name: "trade_buy", visibility: "public", description: "...", handler: handleBuy },
{ name: "trade_sell", visibility: "public", description: "...", handler: handleSell },
{ name: "trade_convert", visibility: "public", description: "...", handler: handleConvert },
{ name: "trade_stats", visibility: "public", description: "...", handler: handleStats },
],
};
export default tradingModule;
Command implementations
trade_topup <amount> [currency=VND]
- Parse:
ctx.match.trim().split(/\s+/)->[amountStr, currencyStr?] - Validate: amount > 0, numeric; currency in CURRENCIES (default VND)
- Get portfolio, add currency
- If currency !== VND: fetch forex rate, add
amount * ratetototalvnd - If currency === VND: add amount to
totalvnd - Save portfolio
- Reply:
Topped up {formatCurrency(amount, currency)}. Balance: {formatCurrency(balance, currency)}
trade_buy <amount> <symbol>
- Parse args: amount + symbol
- Validate: amount > 0; symbol exists in SYMBOLS
- If stock: amount must be integer (
Number.isInteger(parseFloat(amount))) - Fetch price via
getPrice(db, symbol) - Cost = amount * price (in VND)
- Deduct VND from portfolio; if insufficient -> error with current balance
- Add asset to portfolio
- Save, reply with purchase summary
trade_sell <amount> <symbol>
- Parse + validate (same as buy)
- Deduct asset; if insufficient -> error with current holding
- Fetch price, revenue = amount * price
- Add VND to portfolio
- Save, reply with sale summary
trade_convert <amount> <from> <to>
- Parse: amount, from-currency, to-currency
- Validate: both in CURRENCIES, from !== to, amount > 0
- Deduct
fromcurrency; if insufficient -> error - Fetch forex rates, compute converted amount
- Add
tocurrency - Save, reply with conversion summary
trade_stats
- Get portfolio
- Fetch all prices
- For each category, compute current VND value
- Sum all = total current value
- P&L = total current value + currency.VND - totalvnd
- Reply with formatted breakdown table
Arg parsing helper
Extract into a local parseArgs(ctx, specs) at top of file:
specs= array of{ name, required, type: "number"|"string", default? }- Returns parsed object or null (replies usage hint on failure)
- Keeps handlers DRY
Implementation steps
- Create
src/modules/trading/index.js - Module-level
let db = null;set ininit - Implement
parseArgshelper (inline, ~20 lines) - Implement each handler function (~25-35 lines each)
- Wire into
commandsarray - Ensure file stays under 200 lines. If approaching limit, extract
parseArgsto ahelpers.jsfile
Edge cases
| Input | Response |
|---|---|
/trade_buy (no args) |
Usage: /trade_buy <amount> <symbol> |
/trade_buy -5 BTC |
Amount must be positive |
/trade_buy 0.5 NOPE |
Unknown symbol. Supported: BTC, ETH, ... |
/trade_buy 1.5 TCB |
Stock quantities must be whole numbers |
/trade_buy 1 BTC (no VND) |
Insufficient VND. Balance: 0 VND |
/trade_sell 10 BTC (only have 5) |
Insufficient BTC. You have: 5 |
/trade_convert 100 VND VND |
Cannot convert to same currency |
| API failure during buy | Could not fetch price. Try again later. |
Failure modes
| Risk | Likelihood | Impact | Mitigation |
|---|---|---|---|
| File exceeds 200 lines | Medium | Low | Extract parseArgs to helpers.js |
| Price fetch fails mid-trade | Low | Medium | Catch, reply error, don't modify portfolio |
| User sends concurrent commands | Low | Low | Last write wins; acceptable for paper trading |
Success criteria
- All 5 commands registered as public
- Each command validates input and replies helpful errors
- Buy/sell correctly modify both VND and asset balances
- Convert works between VND and USD
- Stats shows breakdown with P&L
- File under 200 lines (or split cleanly)