Tusker FX + SKY Trader
Full-Stack Build Specification
Generated 10/29/2026
Part A — Full Technical Blueprint
Complete, line-level detail: every entity schema, backend function, core library, hook, RLS rule, workflow, and page route required to rebuild both applications from scratch.
A1Data Model — Entities
All persistent data is stored as JSON-schema entities. Every record auto-includes id, created_date, updated_date, created_by_id. Below is every entity, its fields, and its row-level security posture.
ClientAccount
A client's trading account (custom auth, separate from Base44 User).
| Field | Type | Description |
|---|---|---|
| trading_user_id | string | Unique public ID, e.g. TFX-100001 |
| password_hash | string | SHA-256 hash of password + salt |
| full_name | string | Client display name |
| phone_number | string | Contact phone |
| string | Contact email | |
| account_balance | number | Realized balance (deposits − withdrawals + closed P/L) |
| equity | number | Live equity = balance + bonus + floating P/L |
| floating_pl | number | Sum of open position P/L |
| used_margin | number | Margin locked by open positions |
| free_margin | number | Equity − used margin |
| margin_level | number | Equity / used margin × 100 (0 when no positions) |
| account_status | enum | Active | Suspended | Disabled |
| leverage | number | Account leverage, default 100 |
| currency | string | USD (default) |
| account_type | enum | Basic | ECN | Royal | VIP | Demo |
| auto_withdrawal_enabled | boolean | Auto-approve withdrawals if first deposit was USDT/BTC |
| last_login | date-time | Last client login timestamp |
| last_statement_generated_at | date-time | 24h statement cooldown anchor |
| notes | string | Admin notes |
RLS: Open (create/read/update/delete = null) — access controlled at the application layer via client session + admin role checks.
Position
An open or closed trade position.
| Field | Type | Description |
|---|---|---|
| account_id | string | ClientAccount id |
| ticket | string | Unique position ticket |
| symbol | string | Instrument symbol, e.g. EURUSD |
| type | enum | buy | sell |
| volume | number | Lot size |
| open_price | number | Entry price |
| close_price | number | Exit price |
| current_price | number | Live mark |
| stop_loss | number | SL level |
| take_profit | number | TP level |
| profit | number | Realized P/L on close |
| commission | number | Per-trade commission |
| swap | number | Accumulated overnight swap |
| status | enum | open | closed | pending |
| order_type | enum | market | buy_limit | sell_limit | buy_stop | sell_stop |
| close_reason | string | tp | sl | stop_out | neg_balance | manual | ai |
| ai_mode | enum | SAFE | OPTIMIZED (AI session mode, if AI-generated) |
| open_time | date-time | Open timestamp |
| close_time | date-time | Close timestamp (also a race lock) |
RLS: Open — app-layer gated by account ownership / admin role.
Transaction
Deposit or withdrawal request.
| Field | Type | Description |
|---|---|---|
| account_id | string | ClientAccount id |
| type | enum | deposit | withdrawal |
| amount | number | USD amount |
| currency | string | USD |
| status | enum | pending | approved | rejected |
| method | enum | bank_transfer | credit_card | crypto | e_wallet | manual |
| notes | string | Payment details (wallet address, etc.) |
| processed_by | string | Admin who processed |
| processed_at | date-time | Processing timestamp |
RLS: Read/create open; update/delete admin-only (super_admin, admin, broker_admin).
Instrument
A tradable instrument and its contract spec.
| Field | Type | Description |
|---|---|---|
| symbol | string | e.g. EURUSD, BTCUSD |
| name | string | Display name |
| category | enum | forex | metals | crypto | indices | stocks |
| contract_size | number | Lot contract size (forex=100000, gold=100, silver=5000) |
| min_lot / max_lot | number | Lot bounds |
| spread | number | Admin-configurable spread added to ASK |
| commission | number | Per-trade commission |
| swap_long / swap_short | number | Swap points for daily rollover |
| stop_level | number | Min distance for SL/TP |
| digits | number | Price precision (5 forex, 2 crypto/gold) |
| base_price | number | Persisted fallback price (updated every 10 min) |
| manual_price_active | boolean | Super-admin toggle pinning base_price as the live price |
| base_price_locked_until | date-time | Legacy lock window (now manual toggle only) |
| enabled | boolean | Tradable flag |
RLS: Default (no RLS declared) — public read.
AISimulationTier
Admin-configured AI auto-dealing parameters per balance range.
| Field | Type | Description |
|---|---|---|
| tier_name | string | Display label, e.g. "Starter $20-99" |
| min_balance / max_balance | number | Inclusive balance range for this tier |
| daily_profit_min / daily_profit_max | number | Target daily AI profit range (USD) |
| daily_loss_limit | number | Max daily loss before AI pauses (0 = no cap) |
| win_rate | number | Fraction of trades that are wins (0-1), default 0.9 |
| trade_interval_min_sec / max_sec | number | Random cooldown between AI trades |
| lot_size | number | Lot size for AI trades in this tier |
| enabled | boolean | Tier active flag |
| display_order | number | Admin UI sort order |
RLS: Admin-only CRUD (super_admin, admin, broker_admin).
AISession
An active AI trading session for an account.
| Field | Type | Description |
|---|---|---|
| trading_account_id | string | ClientAccount id |
| mode | enum | SAFE | OPTIMIZED |
| status | enum | ACTIVE | STOPPED |
| started_at / stopped_at | date-time | Session bounds |
| total_trades | number | Count of AI deals |
| total_profit / total_loss | number | Cumulative P/L split |
RLS: Open.
AITrade
A single AI-simulated deal (history only — never an open Position).
| Field | Type | Description |
|---|---|---|
| session_id | string | AISession id |
| trading_account_id | string | ClientAccount id |
| symbol | string | Instrument traded |
| side | enum | BUY | SELL |
| lot_size | number | Lot size |
| profit_loss | number | Deal P/L |
| deal_status | enum | WIN | LOSS |
| source | enum | SIMULATOR | ADMIN |
| created_at | date-time | Deal timestamp |
RLS: Open.
PendingOrder
A pending (limit/stop) order awaiting trigger.
| Field | Type | Description |
|---|---|---|
| ticket | string | Order ticket |
| trading_account_id | string | ClientAccount id |
| symbol | string | Instrument |
| order_type | enum | buy_limit | sell_limit | buy_stop | sell_stop |
| volume | number | Lot size |
| trigger_price | number | Activation price |
| stop_loss / take_profit | number | Attached SL/TP |
| status | enum | pending | triggered | cancelled | expired |
| executed_at / executed_price | date-time/number | Fill details |
RLS: Open.
TradingBonus
A bonus credited to an account.
| Field | Type | Description |
|---|---|---|
| trading_account_id | string | ClientAccount id |
| bonus_type | enum | Welcome | Deposit | Trading Credit | Promotional | Manual Adjustment |
| bonus_amount | number | Bonus USD |
| status | enum | ACTIVE | REMOVED | EXPIRED |
| created_by_admin | string | Admin who granted |
RLS: Open.
BonusLedger
Audit trail of every bonus change.
| Field | Type | Description |
|---|---|---|
| trading_account_id | string | ClientAccount id |
| action_type | enum | BONUS_ADDED | REMOVED | EXPIRED | ADJUSTED |
| amount | number | Change amount |
| previous_bonus_balance / new_bonus_balance | number | Balances before/after |
| admin_user | string | Admin responsible |
RLS: Open.
Notification
In-app notification for a client account.
| Field | Type | Description |
|---|---|---|
| trading_account_id | string | ClientAccount id |
| type | enum | TP_HIT | SL_HIT | PENDING_TRIGGERED | DEPOSIT_APPROVED | WITHDRAWAL_APPROVED | BONUS_ADDED | MARGIN_CALL | STOP_OUT | AI_SESSION_STARTED | AI_SESSION_STOPPED | REGISTRATION_REQUEST | DUPLICATE_REGISTRATION | ACCOUNT_UPGRADE |
| title / message | string | Notification content |
| read | boolean | Read flag |
| created_at | date-time | Timestamp |
RLS: Open (create null, read null).
RiskSettings
Global broker risk configuration (single 'global' record).
| Field | Type | Description |
|---|---|---|
| setting_key | string | "global" |
| timezone | string | Display timezone for all client-facing times (IANA), default Asia/Colombo |
| max_leverage | number | Max allowed leverage, default 1000 |
| stop_out_level | number | Margin % triggering stop-out, default 50 |
| margin_call_level | number | Margin % for margin-call warning, default 100 |
| warning_level | number | Warning threshold, default 80 |
| negative_balance_protection | boolean | Close all when equity ≤ 0 |
| max_lot / min_lot | number | Lot bounds |
| hedging_allowed | boolean | Allow hedging |
| swap_enabled / commission_enabled | boolean | Fee toggles |
| bonus_included_in_equity | boolean | Bonus counts toward equity |
RLS: Read open; create/update/delete admin-only.
ClientOffer
A promotional offer popup shown to clients.
| Field | Type | Description |
|---|---|---|
| title / body | string | Offer copy |
| image_url | string | Banner image |
| cta_text / cta_link | string | Call-to-action label + URL |
| target_audience | enum | all | specific |
| target_account_ids | string | Comma-separated account ids (specific) |
| auto_close_seconds | number | Popup auto-close (0 = none) |
| show_interval_hours | number | Min hours between showings |
| status | enum | active | paused | expired |
| start_date / end_date | date-time | Validity window |
| accent_color | string | HSL channels for accent |
RLS: Create/update/delete admin-only; read open.
OfferImpression
Tracks offer views/claims per client.
| Field | Type | Description |
|---|---|---|
| offer_id | string | ClientOffer id |
| client_account_id | string | ClientAccount id |
| last_shown_at | date-time | Last view time |
| view_count | number | Total views |
| claimed | boolean | Client clicked CTA |
| claimed_at | date-time | Claim timestamp |
RLS: Create/read/update open; delete admin-only.
ClientReview
A client review/testimonial.
| Field | Type | Description |
|---|---|---|
| client_account_id | string | ClientAccount id |
| full_name / trading_user_id | string | Reviewer identity (real name shown publicly) |
| rating | number | 1-5 stars |
| remark | string | Review text |
| instrument | string | Traded instrument |
| is_public | boolean | Shown on homepage when approved |
| status | enum | pending | approved | rejected |
| submitted_at / reviewed_at | date-time | Lifecycle timestamps |
RLS: Create/read open; update/delete admin-only.
ClientVerification
KYC document submission.
| Field | Type | Description |
|---|---|---|
| client_account_id | string | ClientAccount id |
| id_proof_front_url / back_url | string | ID front/back |
| address_proof_front_url / back_url | string | Address proof |
| card_front_url / back_url | string | Card images |
| bank_statement_url | string | Bank statement |
| status | enum | pending | verified | rejected |
| verified_by_admin / verified_at | string/date-time | Verification audit |
RLS: Create/read open; update/delete admin-only.
AcademyRegistration
A registration request from the marketing/academy site.
| Field | Type | Description |
|---|---|---|
| full_name / email / phone_number | string | Applicant contact |
| account_type | enum | Basic | ECN | Royal | VIP |
| password_hash | string | SHA-256 hash |
| status | enum | pending | contacted | created | rejected |
| created_trading_user_id | string | Account id once created |
| source | enum | academy | account | deal |
| remark | string | Client-submitted details |
RLS: Create open; read/update admin-only; delete super_admin only.
PaymentMethod
Configured deposit/withdrawal methods.
| Field | Type | Description |
|---|---|---|
| method_type | enum | deposit | withdrawal | both |
| name / method_key | string | Display name + internal key |
| icon | string | Emoji icon |
| min_amount / max_amount | number | Amount bounds |
| fee_percent | number | Fee % |
| instructions | string | Wallet address / bank details shown to client |
| card_link | string | Copyable payment link |
RLS: Read open; CRUD admin-only.
AuditLog
Admin action audit trail.
| Field | Type | Description |
|---|---|---|
| action | string | e.g. ACCOUNT_RESTORE_PRE_TRADEOUT |
| admin_user | string | Admin name |
| account_id | string | Affected account |
| details | string | Action description |
| timestamp | date-time | When |
RLS: Open.
TradingAccount (legacy)
Older account entity tied to Base44 User (RLS-protected).
| Field | Type | Description |
|---|---|---|
| user_id | string | Base44 User id |
| account_number | string | Account number |
| account_type | enum | standard | ecn | vip | demo |
| balance / equity / used_margin / free_margin / margin_level / floating_pl | number | Live metrics |
| status | enum | active | suspended | closed |
RLS: Owner read/update; broker_admin/super_admin all; create/delete admin-only.
User (built-in)
Base44 platform user — admins only. Cannot be created via SDK; users join via invites.
| Field | Type | Description |
|---|---|---|
| id / created_date | string/date | Built-in |
| full_name / email | string | Profile |
| role | string | admin | user (customizable to super_admin, broker_admin) |
RLS: Built-in: only admins list/update/delete others.
A2Backend Functions
Five serverless functions (Deno/TypeScript) handle all server-side automation. Each is invoked via base44.functions.invoke(name, payload) or a scheduled workflow.
backgroundTradingEngine
Schedule: every ~30 seconds via workflow. Auth: service-role (no user context).
The institutional core. Runs even when clients are offline. Three phases per tick:
- AI Auto-Dealing — for each ACTIVE AISession, find the matching AISimulationTier by balance range. Respect cooldown (random within tier interval), daily profit cap, and daily loss limit. Pick a live, open-market symbol, derive per-deal P/L from the tier's daily targets, create an AITrade record (history only — no Position), and adjust balance + session stats.
- TP/SL Monitoring — for every open Position, skip if the asset class market is closed (weekend) or the price isn't live. Close at the TP/SL trigger price (not the bid). Use a unique close_time timestamp as a race lock: re-read the position after update; only the monitor whose timestamp persists applies P/L to the balance. Send TP_HIT/SL_HIT notification + Telegram alert.
- Stop-Out Guard — iterative loop (max 25): recompute equity = balance + bonus + floating P/L using live prices; persist equity/margin metrics. If negative-balance protection and equity ≤ 0, close all positions. If margin level ≤ stop_out_level, liquidate only currently-tradeable (liquid) positions worst-loss-first, re-running until margin normalizes. Two-tier margin alerts (neutral/professional tone).
Manual price override: instruments with manual_price_active=true pin the engine's price to base_price, overriding the live feed.
dailyRolloverEngine
Schedule: once daily (~00:05 ET) via workflow. Auth: admin-only.
Applies overnight swap/financing to every open Position. Rules:
- Currency/Metal: triple swap on Wednesday (3-day weekend settlement).
- Stock/Index: triple swap on Friday (equity weekend settlement).
- Crypto: standard daily swap, no triple rollover.
- Stock financing: APR-based daily fee = (shares × entry × rate%) / 365, default 4% APR.
Swap fee = volume × contract × swapPoints × pointSize × conversionFactor, realized daily against balance.
updateInstrumentBasePrices
Schedule: every 10 minutes via workflow. Auth: service-role.
Fetches live Finnhub REST quotes for all instruments and persists them as Instrument.base_price — the fallback used when live socket data is unavailable (weekend freeze, disconnect, outage). Skips instruments under manual price override.
restoreAccountPreTradeOut
Auth: super_admin only. Payload: { account_id }.
Reopens every Position closed by stop_out or neg_balance, restoring each to its pre-close state, and reverses the booked P/L: new_balance = current_balance − sum(closed_profits). Writes an AuditLog entry.
sendTelegramAlert
Auth: open (called server-side). Payload: { title, message }.
Sends a Markdown-formatted message to the super-admin Telegram chat using TELEGRAM_BOT_TOKEN + TELEGRAM_CHAT_ID secrets. Fire-and-forget from the frontend via base44.functions.invoke.
A3Frontend Core Libraries
lib/marginEngine.js — Broker-grade margin (MT4/MT5 compatible)
All P/L and margin math. Key formulas:
calcPositionMargin(symbol, volume, price, leverage):
contractSize = getContractSize(symbol) // forex=100000, gold=100, silver=5000, crypto/stock/index=1
return (volume * contractSize * price) / leverage
calcPositionPL(symbol, type, volume, openPrice, currentPrice):
direction = type === 'buy' ? 1 : -1
return (currentPrice - openPrice) * contractSize * volume * direction
calcEquity(balance, bonus, floatingPL, bonusIncludedInEquity=true):
return balance + (bonusIncludedInEquity ? bonus : 0) + floatingPL
calcFreeMargin(equity, usedMargin) = equity - usedMargin
calcMarginLevel(equity, usedMargin) = usedMargin > 0 ? (equity / usedMargin) * 100 : Infinity
validateNewOrder({ account, symbol, type, volume, currentPrice, openPositions, priceMap, riskSettings }):
- reject if account suspended/disabled
- enforce min/max lot
- reject if equity <= 0 (negative balance protection)
- reject if marginLevel <= marginCallLevel
- reject if freeMargin < requiredMargin for new positionlib/finnhubService.js — Live market data
REST quote API for initial prices + WebSocket trade stream for real-time updates. Symbol map: forex/metals → OANDA:, crypto → BINANCE:, indices → ^/INDEX:, stocks → ticker. BID = live price; ASK = BID + admin spread. Manual price overrides pin a symbol and skip the live feed. isSymbolLive() tracks which symbols have received a real tick. Indices polled via REST every 10s (no WS). Auto-reconnect on WS close (5s).
lib/marketData.js — Compatibility shim
Re-exports finnhubService functions under legacy names (startMarketData, subscribePrices, getPrice). Also provides async generateCandleData(symbol, timeframe, count) for charts via Finnhub REST candles, with a simulated-candle fallback.
lib/tradingEngine.js — Order validation + formatters
Re-exports marginEngine functions and adds validateOrder() (account status, lot bounds, margin sufficiency, stop-level distance for SL/TP) and helpers: generateTicket(), generateAccountNumber(), formatPrice(), formatMoney(), formatVolume().
lib/clientAuth.js — Custom client session
Separate from Base44 admin auth. SHA-256 password hashing (Web Crypto, salt _zio_salt_2024). Session stored in localStorage (tuskerfx_client_session), auto-logout after 8h inactivity. generateTradingUserId() produces unique TFX-XXXXXX IDs.
lib/statementPdf.js — PDF statement generator
Uses jsPDF + moment. Branded TuskerFX statement with: account summary (balance, equity, total deposits/withdrawals, open count, closed P/L), deposits & withdrawals table, bonus history, AI trading summary (overall stats only — no tier details), client trade history, running positions. Footer: "This Statement is generated by Tusker FX." 24h generation cooldown enforced.
lib/telegramAlert.js + lib/timezone.js + lib/marketStatus.js
telegramAlert.js fire-and-forget wrapper. timezone.js Intl-based formatting in the configured display timezone (default Asia/Colombo). marketStatus.js client-side market-open check mirroring the server's marketHours.
shared/marketHours.ts — Server-side market gating
Asset-class metadata + market-hours logic. isMarketClosedForClass(): non-crypto closes Fri 17:00 ET → Sun 17:00 ET; crypto 24/7/365. symbolCategory(), getInstrumentMeta(), quoteCurrency(), conversionFactor() (USD-base = 1).
A4React Hooks
useLivePrices(openPositions)
Subscribes to the market feed; exposes allLive — true only when every open position has a real live price. Price-dependent metrics stay hidden until the feed connects.
useTPSLMonitor({ accountId, openPositions })
Client-side TP/SL watcher (mirrors backend). Throttled to 2s. Closes at the TP/SL trigger price. Race lock via unique close_time timestamp + re-read confirmation. Skips non-live prices and closed markets. Invalidates React Query caches on close.
useAISimulator({ session, accountId, onTradeExecuted })
Client-side AI deal generator (active while the client is online). Reads AISimulationTier records (falls back to hardcoded tiers). Derives per-trade P/L from daily targets. Creates AITrade records (history only) and adjusts balance. Respects weekend (crypto-only symbols).
useMarginMonitor, usePendingOrderEngine, useClientSync, useAppTimezone
Live margin/equity recalculation, pending-order trigger evaluation, client data sync, and global timezone fetching respectively.
A5Row-Level Security Summary
RLS is declared per entity in base44/entities/*.jsonc. Three patterns:
- Open (null): ClientAccount, Position, Transaction (read/create), Notification, AISession, AITrade, PendingOrder, TradingBonus, BonusLedger, AuditLog, OfferImpression, ClientReview (read/create), ClientVerification (read/create), AcademyRegistration (create), Instrument, PaymentMethod (read), RiskSettings (read) — access controlled at the app layer by session/role.
- Admin-only CRUD: AISimulationTier, RiskSettings (write), PaymentMethod (write), ClientOffer (write), ClientReview (write), ClientVerification (write), AcademyRegistration (read/update), BonusLedger delete.
- Owner + admin: TradingAccount (legacy) — owner reads/updates own records; broker_admin/super_admin full access.
A6Workflows (Scheduled Automations)
Three scheduled workflows drive the backend:
| Workflow | Trigger | Function |
|---|---|---|
| Background Trading Engine | Every ~30s (scheduled) | backgroundTradingEngine |
| Daily Rollover | Once daily ~00:05 ET | dailyRolloverEngine |
| Update Instrument Base Prices | Every 10 min | updateInstrumentBasePrices |
A7Pages & Routes
Full route inventory (src/App.jsx):
| Route | Page | Access |
|---|---|---|
| / | HomePage | Public |
| /features | FeaturesPage | Public |
| /accounts | AccountsPage | Public |
| /markets | MarketsPage | Public |
| /academy | /trading-academy | LearnPage |
| /contact | ContactPage | Public |
| /client-login | ClientLogin | Public (client auth) |
| /client-register | ClientRegister | Public (client auth) |
| /client-dashboard | ClientDashboard | Client session |
| /client-trade | ClientTrade | Client session |
| /client-positions | ClientPositions | Client session |
| /client-history | ClientHistory | Client session |
| /client-wallet | ClientWallet | Client session |
| /client-ai-trading | AITrading | Client session |
| /mobile-terminal | MobileTerminal | Client session |
| /client-bonuses | ClientBonuses | Client session |
| /client-verification | ClientVerification | Client session |
| /client-reviews | ClientReviews | Client session |
| /login | Login | Base44 admin auth |
| /register | Register | Base44 admin auth |
| /forgot-password | ForgotPassword | Base44 admin auth |
| /reset-password | ResetPassword | Base44 admin auth |
| /admin | AdminDashboard | Admin (ProtectedRoute) |
| /admin/trading-accounts | TradingAccountsAdmin | Admin |
| /admin/clients | ClientManagement | Admin |
| /admin/positions | AdminPositions | Admin |
| /admin/transactions | AdminTransactions | Admin |
| /admin/instruments | InstrumentManagement | Admin |
| /admin/risk | RiskControls | Admin |
| /admin/reports | Reports | Admin |
| /admin/ai-trades | AdminAITrades | Admin |
| /admin/bonuses | AdminBonuses | Admin |
| /admin/verification | AdminVerification | Admin |
| /admin/learning-center | LearningCenter | Admin |
| /admin/account-watch | AccountWatch | Admin |
| /admin/reviews | AdminReviews | Admin |
| /admin/offers | AdminOffers | Admin |
Part B — Architecture & Key Logic
A mid-level overview of the system's architecture, data flow, and the core algorithms that govern trading, risk, and automation — enough to rebuild without line-by-line detail.
B1System Architecture
Two co-located apps sharing one codebase and database, separated by route prefix and auth model:
- Tusker FX (Marketing & Academy): public routes (
/,/features,/accounts,/markets,/academy,/contact). Drives registration requests intoAcademyRegistrationfor admin follow-up. No login required. - SKY Trader (Trading Terminal): client portal (
/client-*) using a custom localStorage session (ClientAuthContext), and an admin console (/admin/*) using Base44 platform auth (AuthProvider+ProtectedRoute).
Stack: React 18 + Vite + Tailwind CSS + shadcn/ui on the frontend; Base44 BaaS (entities, functions, workflows, auth) on the backend. Live market data via Finnhub (REST + WebSocket). Admin alerts via Telegram Bot API.
B2Market Data Pipeline
A single source of truth for prices, with a strict live-only trading gate:
- Initialization:
startFinnhub(instruments)seeds prices fromINSTRUMENT_DEFAULTSbase values for instant display, then fetches REST quotes for all symbols. - Live stream: WebSocket subscribes to forex/metals/crypto/stocks. Indices (US30, NAS100, SPX500, GER40, UK100) have no WS — polled via REST every 10s.
- Spread: ASK = BID + admin-configured per-instrument spread (default 0 → BID = ASK).
- Manual override: when
Instrument.manual_price_active=true, the live feed is skipped for that symbol and the price is pinned tobase_price. All consumers compute P/L from the manual price. - isLive gate:
liveSymbolstracks symbols that have received a real tick.useLivePricesexposesallLive; all trading metrics and engine actions stay hidden/dormant until every open position has a live price. - Weekend freeze: non-crypto markets close Fri 17:00 ET → Sun 17:00 ET; the last tick is frozen and TP/SL never fires on frozen assets. Crypto stays 24/7.
- Fallback persistence:
updateInstrumentBasePriceswrites live REST quotes toInstrument.base_priceevery 10 min for use during outages.
B3Margin & P/L Engine
MT4/MT5-compatible calculations, multi-asset:
Required Margin = (volume × contractSize × price) / leverage
forex: contractSize = 100000
gold: contractSize = 100
silver: contractSize = 5000
crypto/stock/index: contractSize = 1
Position P/L = (currentPrice - openPrice) × contractSize × volume × direction
direction = buy ? +1 : -1
Equity = balance + bonus + floatingPL
FreeMargin = equity - usedMargin
MarginLevel = (equity / usedMargin) × 100 (Infinity when no positions)
Balance = deposits - withdrawals + closedPnL (excludes bonus)B4TP/SL & Stop-Out Rules
Two monitors (frontend + backend) run the same logic with a race lock to prevent double-closure:
- Close-price model: BUY closes at BID (sell to close) → TP when bid ≥ TP, SL when bid ≤ SL. SELL closes at ASK → TP when ask ≤ TP, SL when ask ≥ SL.
- Trigger price fill: positions close at the TP/SL level, not the current market price (institutional standard).
- Race lock: a unique
close_timetimestamp is written; after update the position is re-read — only the monitor whose timestamp persisted applies P/L to the balance. Prevents double credit when both monitors race. - Market gate: TP/SL never fires on closed/frozen markets or non-live prices.
- Stop-out: iterative loop liquidates only currently-tradeable (liquid) positions, worst-loss-first, re-running until margin normalizes or no liquid positions remain. Balance may go negative — only equity gates further trading.
- Negative-balance protection: when equity ≤ 0, all positions close and balance reflects realized P/L (not reset to 0).
- Margin alerts: two tiers (approaching stop-out vs. margin call), both neutral and professional in tone.
B5Daily Rollover / Swap
Once-daily financing applied to every open position:
Currency/Metal: triple swap on Wednesday (3-day settlement)
Stock/Index: triple swap on Friday (equity weekend settlement)
Crypto: standard daily swap, no triple rollover
Swap fee = volume × contract × swapPoints × pointSize × conversionFactor
pointSize = 10^(-digits)
Stock financing (APR model):
dailyFee = (shares × entryPrice × APR%) / 365 (default 4% APR)Swap is realized daily against the account balance and accumulated on the Position's swap field.
B6AI Simulation Engine
Automated dealing for active AI sessions, driven by admin-configured tiers:
- For each ACTIVE
AISession, find theAISimulationTierwhose balance range contains the account balance. - Respect cooldown (random within tier's min/max interval seconds) and daily caps (stop if daily P/L ≥ daily_profit_max or ≤ −daily_loss_limit).
- Pick a live, open-market symbol; derive per-deal P/L from the tier's daily targets divided by estimated trades/day.
- Win/loss decided by the tier's
win_rate(default 0.9). - Create an
AITraderecord (history only — never an open Position) and adjust balance + session stats.
Critical invariant: AI simulations appear only as closed history, never as live positions. Tier details are hidden from the client UI.
B7Authentication Flows
Client (custom session)
Admin-only account creation (no self-service). Login validates SHA-256 hash against ClientAccount.password_hash, stores a localStorage session (8h inactivity timeout), and redirects — mobile logins go to /mobile-terminal. ClientProtectedRoute guards all /client-* routes.
Admin (Base44 platform auth)
Email/password + Google OAuth via Base44 AuthProvider. Roles: super_admin, broker_admin, admin. ProtectedRoute gates /admin/*. Registration → OTP → verify → token → redirect.
B8Notification & Telegram Alert Flow
Two parallel channels for every significant event:
- In-app: a
Notificationrecord is created per client account; the clientNotificationCentersubscribes via React Query + realtime subscriptions. - Telegram: critical admin alerts (registration, deposits, withdrawals, margin breaches, stop-outs, client logins) are forwarded to the super-admin chat via the
sendTelegramAlertfunction usingTELEGRAM_BOT_TOKEN+TELEGRAM_CHAT_IDsecrets. Fire-and-forget; never blocks the caller.
B9Statement PDF Generation
Client-triggered, branded PDF via jsPDF, with a 24h-per-account cooldown:
- Account summary: balance, equity, total deposits, total withdrawals, open count, total closed P/L.
- Deposits & withdrawals table; bonus history; AI trading summary (overall stats only).
- Client trade history (full details) + running positions.
- Footer: "This Statement is generated by Tusker FX." Admin adjustments are never disclosed.
Part C — Feature Inventory
A structured inventory of every feature with a one-paragraph summary. Use this layer for scope estimation and feature checklists.
C1Marketing & Academy Site (Tusker FX)
Homepage
Animated forex-themed hero with live BTC price card, floating Telegram CTA, live price ticker, trust strip, popular markets, AI trading showcase, trading academy preview, latest client reviews (fixed deterministic order, real names), how-to-start steps, and contact centers.
Features Page
Detailed breakdown of platform capabilities: multi-asset trading, AI automation, account types, risk management.
Accounts Page
Four-tier account structure (Basic, ECN, Royal, VIP) with leverage, spreads, and minimums.
Markets Page
Instrument catalog across forex, metals, crypto, indices, and stocks with live pricing.
Trading Academy
Course listing with AI-generated video content (credit-gated), category filtering, and progress tracking. Registration requests flow to admin for manual account creation.
Contact Page
Contact form and office/location details.
C2Client Portal (SKY Trader)
Dashboard
Account overview: balance, equity, margin, floating P/L, open positions summary, recent transactions, AI session status, and quick actions.
Trade Terminal
Full trading interface: market watch, price chart (Finnhub candles), order panel (market + pending orders), live positions table with TP/SL modification, and pending orders panel. All metrics gated on live prices.
Positions
Dedicated open-positions view with close, modify TP/SL, and live P/L.
History
Dual-view trade history: combined total P/L header, side-by-side AI vs manual performance sections, win rates, and date-range filtering (timezone-aware).
Wallet
Deposit/withdrawal workflows with method-specific payment detail collection, auto-withdrawal for qualifying accounts, available-balance calculation accounting for margin and floating P/L, and transaction history. Withdrawals locked while positions are open.
AI Trading
Start/stop AI sessions (SAFE/OPTIMIZED modes), live session stats, and AI deal feed. Tier details hidden from the client.
Mobile Terminal
Compact mobile-optimized trading terminal; mobile logins redirect here.
Bonuses
Active bonus balance, bonus history, and ledger.
Verification
KYC document upload (partial uploads allowed; manual admin verification), status tracking.
Reviews
Submit a review (rating + remark + instrument); admins approve for public display with real names.
Notifications
Real-time in-app notification center with copy-to-clipboard, unread badges, and type-specific icons.
Offer Popups
Targeted promotional offers with view/claim tracking, auto-close, and show-interval throttling.
Statement PDF
One-click branded PDF statement with 24h cooldown.
C3Admin Console
Dashboard
Platform-wide KPIs: total clients, AUM, open positions, pending transactions, AI activity.
Trading Accounts Admin
Create/edit/suspend client accounts, reset passwords, change account types, toggle auto-withdrawal, send notifications, and manage wallet payment methods.
Client Management
Review academy registration requests, create accounts from requests, mark contacted/rejected, detect duplicates.
Positions
Monitor/close all positions across clients, bulk close, and filter by account/symbol/status.
Transactions
Approve/reject deposits & withdrawals, manual adjustments, edit/delete any transaction (with balance reversal), reverse approved withdrawals, and auto-withdrawal processing with payment-detail notifications.
Instruments
Full CRUD on tradable instruments: contract specs, spreads, swaps, leverage, digits, and manual price override toggle (pins price until toggled off).
Risk Controls
Global risk settings: max leverage, stop-out/margin-call levels, negative-balance protection, lot bounds, hedging/swap/commission toggles, and global display timezone.
Reports
Aggregate reports across clients, instruments, and time periods.
AI Trades
Review AI-simulated deals; configure AISimulationTier records (balance ranges, daily profit/loss caps, win rates, intervals, lot sizes).
Bonuses
Grant/remove/adjust bonuses with full ledger audit.
Verification
Review KYC submissions, approve/reject with notes.
Account Watch
Real-time super-admin monitor: margin metrics, account status, live floating P/L, last-online tracking, expandable position breakdowns, and client-online Telegram alerts.
Reviews
Approve/reject client reviews for public homepage display (real names, fixed order).
Offers
Create/target promotional offers with audience targeting, scheduling, and a Claims tab tracking engagement and claim rates.
Learning Center
Manage academy courses and AI-generated video content.
Restore Pre-Trade-Out
Super-admin tool to reopen stop-out/neg-balance closures and reverse the booked P/L.
Appendix I — Base44 Implementation Guide
Templates and conventions for rebuilding on the Base44 platform.
I.1Entity Schema Template
Each entity is a JSON-schema object at base44/entities/<Name>.jsonc. Example (ClientAccount, abridged):
{
"name": "ClientAccount",
"type": "object",
"properties": {
"trading_user_id": { "type": "string" },
"password_hash": { "type": "string" },
"full_name": { "type": "string" },
"account_balance": { "type": "number", "default": 0 },
"equity": { "type": "number", "default": 0 },
"account_status": { "type": "string", "enum": ["Active","Suspended","Disabled"], "default": "Active" },
"leverage": { "type": "number", "default": 100 }
},
"required": ["trading_user_id", "password_hash", "full_name"],
"rls": {
"create": null, "read": null, "update": null, "delete": null
}
}Built-in fields id, created_date, updated_date, created_by_id are automatic — never declared. RLS uses user_condition with role and $or for admin tiers.
I.2Backend Function Template
Functions live at base44/functions/<name>/entry.ts (Deno/TypeScript). Pattern:
import { createClientFromRequest } from 'npm:@base44/sdk@0.8.48';
import { secrets } from "base44:runtime";
export default async function(req: Request): Promise<Response> {
const base44 = createClientFromRequest(req);
const user = await base44.auth.me();
// ...logic using base44.asServiceRole.entities.<Name>.filter/create/update
return Response.json({ ok: true });
}Use base44.asServiceRole for service-role access (bypasses RLS). Secrets via secrets.get("NAME"). Invoke from frontend with base44.functions.invoke('name', payload).
I.3Workflow Schedule Reference
Workflows are JSON at base44/workflows/<Name>.jsonc. The three scheduled workflows:
Background Trading Engine → scheduled every ~30s → invoke backgroundTradingEngine
Daily Rollover → scheduled once daily → invoke dailyRolloverEngine
Update Instrument Prices → scheduled every 10 min → invoke updateInstrumentBasePricesI.4Secrets
Two secrets power the Telegram alert channel:
TELEGRAM_BOT_TOKEN— Bot API token from BotFather.TELEGRAM_CHAT_ID— Super-admin chat/channel id (user must/startthe bot first).
Finnhub API key is currently hardcoded in the market-data libs (replace with a secret for production).
I.5SDK Entity Operations
base44.entities.Todo.list('-updated_date', 20)
base44.entities.Todo.filter({status:'active'}, '-created_date', 10)
base44.entities.Todo.create({title:'x'})
base44.entities.Todo.bulkCreate([{...},{...}])
base44.entities.Todo.update(id, {status:'done'})
base44.entities.Todo.updateMany({status:'active'}, {$set:{status:'done'}})
base44.entities.Todo.bulkUpdate([{id, status:'done'}, ...])
base44.entities.Todo.delete(id)
base44.entities.Todo.deleteMany({status:'archived'})
base44.entities.Todo.subscribe((event) => { /* realtime */ })Appendix II — Stack-Agnostic Build Guide
Data model, API contract, auth, and cron jobs for rebuilding on any framework (Next.js, Django, Laravel, NestJS, etc.).
II.1Data Model (SQL/ERD)
Core tables and relationships. All tables have id (uuid PK), created_at, updated_at, created_by_id.
client_accounts (id PK, trading_user_id UNIQUE, password_hash, full_name,
email, phone_number, account_balance, equity, floating_pl, used_margin,
free_margin, margin_level, account_status, leverage, currency, account_type,
auto_withdrawal_enabled, last_login, last_statement_generated_at)
positions (id PK, account_id FK→client_accounts, ticket, symbol, type,
volume, open_price, close_price, current_price, stop_loss, take_profit,
profit, commission, swap, status, order_type, close_reason, ai_mode,
open_time, close_time)
transactions (id PK, account_id FK→client_accounts, type, amount, currency,
status, method, notes, processed_by, processed_at)
instruments (id PK, symbol UNIQUE, name, category, contract_size, min_lot,
max_lot, spread, commission, swap_long, swap_short, stop_level, digits,
base_price, manual_price_active, enabled)
ai_simulation_tiers (id PK, tier_name, min_balance, max_balance,
daily_profit_min, daily_profit_max, daily_loss_limit, win_rate,
trade_interval_min_sec, trade_interval_max_sec, lot_size, enabled)
ai_sessions (id PK, trading_account_id FK→client_accounts, mode, status,
started_at, stopped_at, total_trades, total_profit, total_loss)
ai_trades (id PK, session_id FK→ai_sessions, trading_account_id, symbol,
side, lot_size, profit_loss, deal_status, source, created_at)
pending_orders (id PK, trading_account_id, symbol, order_type, volume,
trigger_price, stop_loss, take_profit, status, created_at, executed_at,
executed_price)
trading_bonuses (id PK, trading_account_id, bonus_type, bonus_amount,
status, created_by_admin, created_at)
bonus_ledger (id PK, trading_account_id, action_type, amount,
previous_bonus_balance, new_bonus_balance, admin_user, created_at)
notifications (id PK, trading_account_id, type, title, message, read, created_at)
risk_settings (id PK, setting_key UNIQUE, timezone, max_leverage,
stop_out_level, margin_call_level, warning_level,
negative_balance_protection, max_lot, min_lot, hedging_allowed,
swap_enabled, commission_enabled, bonus_included_in_equity)
client_offers (id PK, title, body, image_url, cta_text, cta_link,
target_audience, target_account_ids, auto_close_seconds,
show_interval_hours, status, start_date, end_date)
offer_impressions (id PK, offer_id FK→client_offers, client_account_id,
last_shown_at, view_count, claimed, claimed_at)
client_reviews (id PK, client_account_id, full_name, trading_user_id,
rating, remark, instrument, is_public, status, submitted_at, reviewed_at)
client_verifications (id PK, client_account_id, id_proof_front_url,
id_proof_back_url, address_proof_front_url, address_proof_back_url,
card_front_url, card_back_url, bank_statement_url, status,
verified_by_admin, verified_at)
academy_registrations (id PK, full_name, email, phone_number, account_type,
password_hash, status, created_trading_user_id, source, remark)
payment_methods (id PK, method_type, name, method_key, icon, enabled,
min_amount, max_amount, fee_percent, instructions, card_link)
audit_logs (id PK, action, admin_user, account_id, details, timestamp)
users (platform auth — admin only; not client accounts)II.2REST API Contract
On Base44 these are SDK calls; on a custom backend they map to REST endpoints. Auth via Bearer token (client session or admin JWT).
# Client auth (custom)
POST /api/client/login { trading_user_id, password } → { session_token }
POST /api/client/logout → { ok }
GET /api/client/me → { account }
# Accounts (admin)
GET /api/admin/accounts ?status=&q=
POST /api/admin/accounts { full_name, account_type, leverage }
PATCH /api/admin/accounts/:id { ...fields }
POST /api/admin/accounts/:id/reset-password
POST /api/admin/accounts/:id/notify { title, message }
POST /api/admin/accounts/:id/restore-pre-tradeout (super_admin)
# Positions
GET /api/positions?account_id=&status=
POST /api/positions { account_id, symbol, type, volume, ... }
PATCH /api/positions/:id { stop_loss, take_profit } | { status:'closed', ... }
POST /api/admin/positions/bulk-close { ids }
# Transactions
GET /api/transactions?account_id=&status=
POST /api/transactions { account_id, type, amount, method, notes }
PATCH /api/transactions/:id { status, amount, method, notes } (admin)
DELETE /api/transactions/:id (admin)
POST /api/transactions/:id/reverse (admin)
# Instruments
GET /api/instruments
POST /api/instruments (admin)
PATCH /api/instruments/:id { spread, base_price, manual_price_active, ... }
# AI
GET /api/ai-sessions?account_id=
POST /api/ai-sessions { trading_account_id, mode }
PATCH /api/ai-sessions/:id { status }
GET /api/ai-trades?account_id=
GET /api/ai-tiers POST/PATCH/DELETE (admin)
# Risk
GET /api/risk-settings
PATCH /api/risk-settings (admin)
# Market data (or use Finnhub directly client-side)
GET /api/prices → { symbol: { bid, ask, isLive, ... } }
GET /api/prices/:symbol/candles?tf=1H&count=80
# Notifications
GET /api/notifications?account_id=
PATCH /api/notifications/:id { read:true }
# Offers / Reviews / Verification / Bonuses / KYC — standard CRUD per entity
# Statements
POST /api/statements/generate { account_id } → PDF (24h cooldown)II.3Authentication Flow
Client (custom)
1. Admin creates ClientAccount (password hashed SHA-256 with salt).
2. Client POST /api/client/login { trading_user_id, password }.
3. Server hashes password, compares to password_hash, issues session token (JWT or opaque).
4. Client stores token (localStorage); 8h inactivity expiry.
5. ClientProtectedRoute guards /client-* routes.
6. Mobile logins redirect to /mobile-terminal.Admin (platform auth)
1. Register { email, password } → user created (unverified).
2. OTP sent → verifyOtp → access token issued.
3. Token stored; ProtectedRoute guards /admin/*.
4. Roles: super_admin, broker_admin, admin — enforced in RLS / route guards.
5. Google OAuth alternative login.II.4Cron Jobs / Scheduled Tasks
Every 30s: backgroundTradingEngine
- AI auto-dealing for ACTIVE sessions (tier-matched)
- TP/SL monitoring + close (race-locked)
- Stop-out / negative-balance protection (iterative, liquid-only)
Once daily (~00:05 ET): dailyRolloverEngine
- Apply swap/financing to all open positions
- Triple swap: Wed (fx/metals), Fri (stocks/indices)
Every 10 min: updateInstrumentBasePrices
- Fetch Finnhub REST quotes → persist as Instrument.base_price (fallback)
- Skip manual-override instrumentsII.5External Services
- Finnhub — REST quote API + WebSocket trade stream. Symbol map: OANDA: (fx/metals), BINANCE: (crypto), ^/INDEX: (indices), ticker (stocks). API key required.
- Telegram Bot API — super-admin alerts via
sendMessage. Requires bot token + chat id; recipient must/startthe bot. - jsPDF + moment — client-side statement PDF generation.