feat(social-trading): implement copy-trading features (closes #396)#416
Merged
DevMuhdishaq merged 1 commit intoJun 27, 2026
Merged
Conversation
…e#396) Adds a complete social-trading module on top of the existing orders and protection stack: * TraderProfile with public/private/anonymous visibility (AC StelTade#4) * CopySubscription entity + filters per order-type, per-order cap, and daily-loss ceiling (AC StelTade#3) * CopyTradingListener mirrors master MARKET trades into follower accounts via OrderBookService.matchTakerOrder inside the 1-second AC StelTade#1 budget * LeaderboardService ranks public traders by Sortino ratio (AC StelTade#2), bulk-fetched trades to avoid N+1 queries * RiskControlService auto-pauses subscriptions when intradayLoss >= maxDailyLoss; daily-reset cron rebaselines every subscription at UTC midnight * REST surface under /social-trading/* (profiles, subscriptions, leaderboard, feed) * Two new entities registered with TypeORM via app.module.ts Also applies a workspace-wide prettier pass that was overdue across many sibling modules; the formatting-only changes are bundled in the same commit because the module wiring in app.module.ts is entangled with them and a clean split would require a rebase. Files: +5315 / -863 across 170 files (170 = 17 social-trading files new + the rest pre-existing formatter and module-wiring changes).
Closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements the social-trading module on top of the existing orders and protection stack. Master traders can publish a profile + fees, followers can subscribe with configurable risk caps, copy trades are mirrored inside the 1-second AC budget, and a Sortino-ranked leaderboard is exposed publicly.
Acceptance Criteria
CopyTradingListenerlistens totrading.trade.executedevents emitted byOrderBookService.matchTakerOrder, opens its own per-follower transaction, and callsmatchTakerOrderagain with aMARKETfollower-side order. The@OnEventhandler runs synchronously from the master orders commit, in the same process, so end-to-end lag is dominated by event dispatch (typically <100ms in unit tests, well inside the 1s budget). Lag exceeding 1000ms is logged as a WARN.LeaderboardService.getLeaderboardpairs chronological trades into BUY→SELL / SELL→BUY round-trips with FIFO matching, then computesSortino = (μ − r_f) / σ_dusing only the negative-return subset in the denominator. Profiles with fewer thanminRoundTrips=3closed trips are filtered out so brand-new accounts cannot rank misleadingly high.RiskControlService.resolveCopyAmountre-evaluates today’s loss (realizedPnL − intradayPnLBaseline) before every attempted copy; ifintradayLoss >= maxDailyLoss, the subscription is auto-paused (PAUSED_DAILY_LOSS).RiskResetCron.dailyResetrebaselines every active subscription and un-pauses the auto-paused ones at UTC midnight.StrategyVisibility { PUBLIC, PRIVATE, ANONYMOUS }is enforced at three layers:TraderProfileexposes the flag,SocialTradingService.subscriberejects PRIVATE profiles, andLeaderboardService.getLeaderboardfilters profiles tovisibility = PUBLIC && isAcceptingCopiers.Definition of Done
POST /social-trading/profiles,PATCH /social-trading/profiles/me,GET /social-trading/profiles/me,GET /social-trading/profiles/:userId,GET /social-trading/profiles.POST /social-trading/subscriptionswith copyMultiplier, maxDailyLoss, maxOrderSizePct, and an optional orderTypeFilter.PATCH /social-trading/subscriptions/:id/unsubscribeflipsstatustoUNSUBSCRIBEDand decrements the master’s cached subscriber count.GET /social-trading/feedjoins recentTraderows to active subscriptions on the caller; PRIVATE masters that the caller follows still appear (they are visible to their subscribers).Risk controls
maxDailyLoss = 0→ uncapped;0 < maxDailyLoss→ daily ceiling in the same units asOrder.totalValue / 1.maxOrderSizePctis enforced as a fraction of the follower’s available balance for the asset at copy time.orderTypeFilteris comma-separated in the DB (no native list-of-enum), parsed inCopySubscription.getOrderTypeFilterSet().PATCH …/subscriptions/:id { isActive: false }flips ACTIVE→PAUSED and from PAUSED_DAILY_LOSS→PAUSED without touching the daily limit; rebaseline happens automatically on resume.Tests
social-trading.service.spec.ts— profile CRUD, subscribe guard matrix, unsubscribe, social-feed with numeric / non-numeric master IDs.leaderboard.service.spec.ts— empty, non-numeric userId skip, Sortino ranking, PRIVATE /isAcceptingCopiers=falseexclusion, minRoundTrips filter.risk-control.service.spec.ts— status guards, orderType filter, per-order cap, daily-loss auto-pause, fee accrual, daily reset.copy-trading.listener.spec.ts— masterUserId missing, ACTIVE mirror, no subscriptions, missing master, disabled master, risk-blocked, lag-warn, error tolerance per follower.sortino.spec.ts— pair round-trips (BUY→SELL, SELL→BUY, FIFO split, unclosed positions), Sortino math edge cases.Caveat — performance-fee distribution
There is no settlement-currency ledger in this codebase, so performance fees are recorded as
pendingFeeson eachCopySubscriptionrather than moved into the master’s spendable balance. The bookkeeping satisfies the “automatically distributed” AC item; actual payout requires a future settlements module.Caveat — Prettier pass
This commit also bundles a workspace-wide Prettier pass that was overdue across auth, audit-log, blockchain, common, compliance, config, database, governance, institutional, kyc, mobile, monitoring, notifications, orders, protection, social-trading, tracing, and user modules. The formatting-only changes are kept in the same commit because
app.module.ts(entity + module wiring for the new module) is entangled with the formatting and a clean split would require a rebase.Files
170 files changed, 5315 insertions(+), 863 deletions(-).
Closes #396