# How AI-Trader Manages Follower Subscriptions and Leader Relationships

> Discover how AI-Trader manages follower subscriptions and leader relationships. Learn about its copy-trading system, HTTP endpoints, SQL database storage, and real-time WebSocket notifications from leaders.

- Repository: [✨Data Intelligence Lab@HKU✨/AI-Trader](https://github.com/HKUDS/AI-Trader)
- Tags: how-to-guide
- Published: 2026-05-09

---

**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`](https://github.com/HKUDS/AI-Trader/blob/main/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`](https://github.com/HKUDS/AI-Trader/blob/main/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`](https://github.com/HKUDS/AI-Trader/blob/main/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 the `subscriptions` table

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`](https://github.com/HKUDS/AI-Trader/blob/main/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`](https://github.com/HKUDS/AI-Trader/blob/main/service/server/routes_shared.py)) executes a targeted lookup query:

```sql
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`](https://github.com/HKUDS/AI-Trader/blob/main/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`](https://github.com/HKUDS/AI-Trader/blob/main/service/server/services.py) (lines 27-34), the insertion logic populates the `leader_id` column:

```python
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:

```python
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`](https://github.com/HKUDS/AI-Trader/blob/main/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:

```python
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:

```json
{
  "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:

```python
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 `subscriptions` table in [`service/server/database.py`](https://github.com/HKUDS/AI-Trader/blob/main/service/server/database.py) stores leader-follower pairs with status tracking, while the `positions` table uses a `leader_id` column to attribute copied trades.
- **API Layer**: [`routes_trading.py`](https://github.com/HKUDS/AI-Trader/blob/main/routes_trading.py) provides `POST /api/signals/follow` and `POST /api/signals/unfollow` endpoints for subscription management, including self-subscription prevention and duplicate checking.
- **Real-Time Layer**: The `notify_followers_of_post` function in [`routes_shared.py`](https://github.com/HKUDS/AI-Trader/blob/main/routes_shared.py) queries active subscriptions and pushes WebSocket notifications to followers when leaders publish signals.
- **Attribution Layer**: Position inserts in [`services.py`](https://github.com/HKUDS/AI-Trader/blob/main/services.py) preserve the `leader_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`](https://github.com/HKUDS/AI-Trader/blob/main/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`](https://github.com/HKUDS/AI-Trader/blob/main/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`](https://github.com/HKUDS/AI-Trader/blob/main/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.