Jump to content

Connect Leeroopedia MCP: Equip your AI agents to search best practices, build plans, verify code, diagnose failures, and look up hyperparameter defaults.

Heuristic:HKUDS AI Trader Position File Locking

From Leeroopedia




Knowledge Sources
Domains Concurrency, Trading
Last Updated 2026-02-09 14:00 GMT

Overview

POSIX file-based locking (fcntl.flock) to serialize concurrent position file updates, preventing race conditions when multiple agent instances trade the same portfolio simultaneously.

Description

When running multiple agents in parallel (via main_parrallel.py), each agent operates on its own position file (position.jsonl). However, within a single agent's trading session, buy and sell operations must be atomic: reading the current position, calculating the new position, and writing the update must happen without interleaving. The _position_lock() context manager uses POSIX fcntl.flock(LOCK_EX) to acquire an exclusive file lock per signature (model name), preventing data corruption from concurrent MCP tool calls.

Usage

This heuristic is automatically applied in all buy() and sell() MCP tool functions. When extending the trading tools or adding new position-modifying operations, wrap the critical section with _position_lock(signature). Note: this only works on POSIX systems (Linux, macOS).

The Insight (Rule of Thumb)

  • Action: Wrap all position read-modify-write operations in with _position_lock(signature):.
  • Value: Exclusive lock per agent signature via .position.lock file.
  • Trade-off: Serializes all trades for a given agent, reducing parallelism within one agent. This is acceptable since trading decisions are sequential per agent.

Reasoning

JSONL files are append-only by design, but reading the latest position and then appending an updated position is a two-step operation vulnerable to TOCTOU (time-of-check-time-of-use) race conditions. Without locking, two concurrent buy/sell calls could read the same "latest position" and both write updates based on stale data. File-based locking was chosen over database locks because it requires no additional infrastructure and aligns with the file-based data storage pattern used throughout the project.

Code Evidence

Position lock implementation from agent_tools/tool_trade.py:23-52:

def _position_lock(signature: str):
    """Context manager for file-based lock to serialize position updates per signature."""
    class _Lock:
        def __init__(self, name: str):
            log_path = get_config_value("LOG_PATH", "./data/agent_data")
            if os.path.isabs(log_path):
                base_dir = Path(log_path) / name
            else:
                if log_path.startswith("./data/"):
                    log_rel = log_path[7:]  # strip "./data/"
                else:
                    log_rel = log_path
                base_dir = Path(project_root) / "data" / log_rel / name
            base_dir.mkdir(parents=True, exist_ok=True)
            self.lock_path = base_dir / ".position.lock"
            self._fh = open(self.lock_path, "a+")
        def __enter__(self):
            fcntl.flock(self._fh.fileno(), fcntl.LOCK_EX)
            return self
        def __exit__(self, exc_type, exc, tb):
            try:
                fcntl.flock(self._fh.fileno(), fcntl.LOCK_UN)
            finally:
                self._fh.close()
    return _Lock(signature)

Lock usage in buy operation from agent_tools/tool_trade.py:134:

with _position_lock(signature):
    try:
        current_position, current_action_id = get_latest_position(today_date, signature)
    except Exception as e:
        # ... error handling

Related Pages

Page Connections

Double-click a node to navigate. Hold to expand connections.
Principle
Implementation
Heuristic
Environment