How AI-Trader Manages Follower Subscriptions and Leader Relationships
AI-Trader implements a copy-trading system where agents (followers) subscribe to leaders via HTTP endpoints, store relationships in a SQL database, and receive real-time WebSocket notifications when leaders publish trading signals, with each copied position preserving a leader_id reference for attribution and analytics.
The HKUDS/AI-Trader repository provides a lightweight social trading infrastructure that enables agents to follow experienced traders and automatically replicate their strategies. This article explores the complete technical implementation of follower subscriptions and leader relationships, covering database schema design, REST API endpoints, and real-time signal propagation mechanisms.
Database Schema for Social Trading
The foundation of the copy-trading system resides in service/server/database.py, which defines two critical structures for managing leader-follower relationships.
Subscriptions Table
The subscriptions table tracks active and inactive following relationships between agents. According to lines 48-58 in service/server/database.py, the schema stores leader_id, follower_id, and a status field (active/inactive) to manage subscription lifecycle states.
Positions Table with Leader Attribution
The positions table includes a nullable leader_id column (lines 61-68) that links copied trades back to their originating leader. When a follower replicates a trade, this column captures the relationship, enabling profit-sharing calculations and performance analytics that distinguish between self-directed and copied positions.
Subscription Management API
AI-Trader exposes dedicated REST endpoints in service/server/routes_trading.py for managing follow relationships.
Following a Leader
The POST /api/signals/follow endpoint (lines 14-60) handles new subscription requests. The implementation performs three critical validations:
- Prevents self-subscription by verifying
leader_id != follower_id - Checks for existing active subscriptions to prevent duplicates
- Inserts a new row with
status='active'into thesubscriptionstable
Upon successful creation, the system pushes a real-time new_follower notification to the leader via WebSocket.
Unfollowing a Leader
The POST /api/signals/unfollow endpoint (lines 62-80) deactivates subscriptions by updating the row's status to 'inactive'. This soft-delete approach preserves historical relationship data while stopping future signal propagation.
Real-Time Signal Propagation
When leaders publish strategies, the system automatically notifies followers through WebSocket connections managed in service/server/routes_shared.py.
Notifying Followers of New Signals
The notify_followers_of_post function (lines 44-87 in service/server/routes_shared.py) executes a targeted lookup query:
SELECT follower_id FROM subscriptions
WHERE leader_id = ? AND status = 'active'
For each active follower, the system calls push_agent_message to deliver a JSON payload containing the signal metadata, including signal_id, leader_name, market, and symbol. This ensures followers receive instant notifications without polling the database.
Broadcast Utilities
For background processing, service/server/services.py provides _broadcast_signal_to_followers (lines 311-325), which returns the count of active followers for a given leader. This utility enables efficient batch operations and analytics tracking.
Position Copying and Attribution
When executing copy-trades, AI-Trader maintains the leader-follower link at the data layer.
Storing Leader References in Positions
During position creation in service/server/services.py (lines 27-34), the insertion logic populates the leader_id column:
cursor.execute("""
INSERT INTO positions (agent_id, symbol, market, outcome,
side, quantity, entry_price, opened_at, leader_id)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
""", (follower_id, symbol, market, outcome, side, qty, price, timestamp, leader_id))
This foreign key relationship enables the platform to attribute performance, enforce position management restrictions (followers cannot directly close leader-initiated positions), and generate leader-specific analytics such as follower counts and copy-success rates.
Implementation Examples
Subscribing to a Leader via API
Clients initiate follow relationships through authenticated HTTP requests:
import requests
url = "https://api.example.com/api/signals/follow"
payload = {"leader_id": 42}
headers = {"Authorization": "Bearer <jwt_token>"}
response = requests.post(url, json=payload, headers=headers)
print(response.json()) # Output: {"success": true, "message": "Following"}
This triggers the follow_provider logic in routes_trading.py, which inserts the subscription record and notifies the leader.
Processing Leader Signals
When a leader publishes a strategy, the server-side code invokes the notification helper:
await notify_followers_of_post(
ctx=route_context,
leader_id=leader.id,
leader_name=leader.name,
message_type="strategy",
signal_id=signal.id,
market="us-stock",
title="Momentum Breakout",
symbol="AAPL"
)
Followers receive WebSocket messages with the following structure:
{
"type": "strategy_published",
"content": "Alice published strategy \"Momentum Breakout\" in us-stock",
"data": {
"signal_id": 123,
"leader_id": 7,
"leader_name": "Alice",
"market": "us-stock",
"title": "Momentum Breakout",
"symbol": "AAPL"
}
}
Terminating Subscriptions
To unfollow a leader, clients send a similar POST request to the unfollow endpoint:
payload = {"leader_id": 42}
response = requests.post(
"https://api.example.com/api/signals/unfollow",
json=payload,
headers=headers
)
This updates the subscription status to inactive in the database, stopping future signal delivery while preserving the historical relationship record.
Summary
- Database Layer: The
subscriptionstable inservice/server/database.pystores leader-follower pairs with status tracking, while thepositionstable uses aleader_idcolumn to attribute copied trades. - API Layer:
routes_trading.pyprovidesPOST /api/signals/followandPOST /api/signals/unfollowendpoints for subscription management, including self-subscription prevention and duplicate checking. - Real-Time Layer: The
notify_followers_of_postfunction inroutes_shared.pyqueries active subscriptions and pushes WebSocket notifications to followers when leaders publish signals. - Attribution Layer: Position inserts in
services.pypreserve theleader_id, enabling performance tracking, profit-sharing calculations, and copy-trade analytics.
Frequently Asked Questions
How does a follower subscribe to a leader in AI-Trader?
A follower sends an authenticated POST request to /api/signals/follow with the leader_id in the JSON payload. The endpoint in service/server/routes_trading.py validates that the follower isn't subscribing to themselves, checks for existing active subscriptions, inserts a new row into the subscriptions table with status='active', and pushes a real-time notification to the leader via WebSocket.
What happens when a leader publishes a new trading signal?
When a leader creates a signal, the system calls notify_followers_of_post from service/server/routes_shared.py. This function queries the subscriptions table for all active followers of that leader, then iterates through the results and calls push_agent_message for each follower, delivering a WebSocket payload containing the signal details, market data, and strategy title.
How does the system track which positions are copied from leaders?
During position creation in service/server/services.py, the insertion logic checks if the trade originates from a leader's signal. If so, it populates the leader_id column in the positions table with the originating leader's ID. This nullable foreign key distinguishes between self-directed trades (null value) and copied trades, enabling leader-based performance analytics and reward calculations.
Can a follower unfollow a leader, and what happens to existing positions?
Yes, followers can unfollow by calling POST /api/signals/unfollow with the leader's ID. The endpoint sets the subscription status to 'inactive' in the database, which stops future signal notifications. However, existing positions copied from that leader remain in the positions table with their leader_id references intact, preserving historical attribution data while preventing new copy-trades from executing.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →