Skip to content

Repository files navigation

AML-Sim

AML-Sim is an experiment layer on top of the StockSim market simulator. The goal is to study market decision making, robustness, and behavioral finance in synthetic multi-agent markets while keeping scenario orchestration outside the StockSim submodule.

simulators/StockSim is a git submodule. Changes inside StockSim are committed and pushed from that directory, then the parent AML-Sim repository commits the updated submodule pointer.

Built On StockSim

AML-Sim builds on top of StockSim, which is included as a git submodule under simulators/StockSim. StockSim provides the core market simulation engine, exchange agents, trader framework, RabbitMQ-based coordination, and YAML-driven simulation launcher.

This repository adds AML-specific scenario orchestration and synthetic market participants for studying market behavior, robustness, and decision making.

Repository Layout

AML-Sim/
├── aml_runner.py                       # AML scenario runner
├── aml_sim/
│   ├── launcher.py                     # AML-owned StockSim component launcher
│   ├── reporting.py                    # AML-owned report orchestration
│   ├── runs.py                         # AML run directory/artifact helpers
│   ├── scenario.py                     # AML scenario loading/validation
│   └── agents/                         # AML-specific trader agents
│       ├── base.py                     # Shared fast/slow-loop AML agent base
│       ├── market_maker_trader.py      # AML market-maker agent
│       ├── retail_trader.py            # AML retail trader agent
│       ├── institutional_trader.py     # AML institutional trader agent
│       ├── informed_trader.py          # AML informed trader agent
│       ├── liquidity_taker.py          # AML liquidity-taking flow agent
│       ├── shock_agent.py              # AML scenario shock/event broadcaster
│       ├── models/
│       │   ├── profile.py              # Stable role/personality profile models
│       │   └── state.py                # Role-specific strategy state models
│       ├── context/
│       │   ├── observation.py          # LLM/slow-loop observation context
│       │   └── memory.py               # Local memory + future Zep hook
│       └── strategy/
│           ├── llm_slow_strategy.py    # LLM-shaped slow-loop strategist
│           └── validator.py            # Strategy state bounds validation
├── scenarios/
│   └── aml_orderbook_replay.yaml       # Current AML smoke scenario
└── simulators/
    └── StockSim/                       # StockSim submodule
        ├── main_launcher.py            # StockSim entrypoint
        └── docker-compose.yml          # RabbitMQ + StockSim services

Architecture

AML-Sim is split into two layers:

  • Run orchestration: AML-Sim reads scenarios, creates run artifacts, and starts StockSim engine components.
  • Agent behavior: AML-Sim owns the market-maker, retail, and institutional trader behavior while keeping those agents compatible with StockSim's TraderAgent.

Run Orchestration

  1. aml_runner.py reads an AML scenario YAML file.
  2. The scenario's stocksim_config section is extracted and written to .aml_runs/<run-id>/stocksim_config.yaml.
  3. AML-Sim also archives the original scenario as .aml_runs/<run-id>/scenario.yaml and writes run metadata to .aml_runs/<run-id>/metadata.json.
  4. AML-Sim imports StockSim exchange/base-trader/simulation-clock classes and starts those component processes itself. The AML agent behavior classes live under aml_sim/agents/. simulators/StockSim/main_launcher.py remains StockSim's standalone CLI entrypoint.
  5. AML-Sim starts the exchange agents, trader agents, and simulation clock.
  6. Components communicate through RabbitMQ.
  7. Logs for AML-launched runs are written under .aml_runs/<run-id>/logs.

The scenario YAML is the experiment definition. It contains AML-level metadata such as name, description, and rabbitmq_host, plus the stocksim_config mapping that is passed directly into StockSim after generation. In other words, the YAML file is where you configure instruments, exchange mode, agents, simulation times, and environment settings for a StockSim run.

Agent Layer

The AML agent layer currently includes these synthetic market participants:

  • AML_Market_Maker: posts bid/ask limit orders around a configurable fair price and adjusts quotes with an inventory skew.
  • AML_Retail_Trader: submits occasional small noisy market orders with a configurable buy bias and trade probability.
  • AML_Institutional_Trader: works toward target positions using sliced child orders.
  • AML_Informed_Trader: trades from a private/fundamental value signal when the signal is strong enough.
  • AML_Liquidity_Taker: submits directional flow against available liquidity with bounded size and inventory exposure.
  • AML_Shock_Agent: emits scheduled, announced, and random AML shock/event messages to target agents.
  • aml_orderbook_replay.yaml: runs a short synthetic AAPL order book scenario with one market maker, five retail traders, and one institutional trader.
  • aml_agent_infra_smoke.yaml and aml_one_hour_live.yaml: exercise the broader AML agent set, including informed flow, liquidity-taking flow, and scheduled shock events.

These AML agents live in aml_sim/agents/. They still inherit StockSim's TraderAgent and use StockSim's order/message primitives, but AML-Sim owns their behavior and maps YAML types such as AML_Market_Maker to these classes.

AML agents now use a shared fast-loop / slow-loop architecture:

  • BaseAMLAgent inherits from StockSim's TraderAgent and keeps the shared AML agent plumbing in one place.
  • StockSim still owns execution, messaging, portfolio/accounting state, order state, and RabbitMQ integration.
  • AML-Sim owns behavioral strategy state, observation packaging, memory hooks, strategy validation, slow-loop strategy updates, and role-specific fast execution behavior.
  • action_interval controls how often the fast loop is allowed to submit orders.
  • slow_loop_interval controls how often the slow loop updates the agent's strategy state.

The fast loop is role-specific and runs from the currently validated strategy state:

  • Market maker fast loop refreshes bid/ask quotes using fair price, spread, quote size, target inventory, and inventory skew.
  • Retail fast loop submits small probabilistic market orders using trade probability, buy bias, and max order size.
  • Institutional fast loop works toward target positions using child order size, order type, and execution style.

The slow loop uses aml_sim/agents/strategy/llm_slow_strategy.py. By default it uses fixed role-specific JSON responses so the control flow can be tested without spending API credits. Agents can opt into real OpenAI calls through scenario YAML by setting slow_strategist.type: openai.

Strategy State And Validation

Role-specific strategy states live in aml_sim/agents/models/state.py:

  • MarketMakerStrategyState
  • RetailStrategyState
  • InstitutionalStrategyState
  • InformedStrategyState
  • LiquidityTakerStrategyState

Before a strategy proposal is applied, aml_sim/agents/strategy/validator.py checks bounds such as trade probability, buy bias, quote size, spread, child order size, confidence, and risk mode. If validation fails, the agent keeps its previous strategy state and logs the rejection.

Risk Modes And Fast-Loop Policy

Every AML strategy state defaults to risk_mode: normal. Experiments can set a different initial posture in an agent's YAML parameters:

parameters:
  risk_mode: conservative

For an OpenAI slow strategist with an explicit allowed_strategy_fields allowlist, include risk_mode to let the LLM change the posture dynamically:

slow_strategist:
  type: openai
  allowed_strategy_fields:
    - risk_mode

Risk modes map to a normalized risk-aversion value, gamma:

Risk mode gamma
risk_off 3.00
conservative 1.50
normal 1.00
opportunistic 0.75
aggressive 0.50

The shared fast-loop policy derives these values from gamma:

  • participation multiplier: clamp(1 / gamma, 0.25, 1.50)
  • order-size multiplier: clamp(1 / sqrt(gamma), 0.40, 1.40)
  • position-limit multiplier: clamp(1 / gamma, 0.25, 1.00)
  • signal-threshold multiplier: clamp(sqrt(gamma), 0.70, 2.00)

clamp(value, minimum, maximum) restricts a result to the stated range. normal therefore produces 1.0 multipliers and preserves existing behavior. The policy is composed with, rather than substituted for, event pressure:

effective fast-loop behavior =
    configured strategy × event pressure × risk-mode policy

The common preference produces role-specific behavior:

  • market makers adjust quote size, maximum inventory, spread, and inventory-based price skew;
  • retail traders adjust participation probability and maximum order size;
  • informed traders adjust participation, order size, position limit, and the signal strength required to trade;
  • liquidity takers adjust participation, order size, and inventory limit;
  • institutional traders use smaller child orders when adding exposure, but higher risk aversion accelerates child orders that reduce existing exposure.

The relationships are informed by Merton-style portfolio choice, Avellaneda-Stoikov market making, and Almgren-Chriss execution. The mode values are normalized simulation categories because those source models use differently scaled risk parameters.

Slow-loop memory records strategy_before and strategy_after, including risk_mode. Submitted, rejected, and executed order artifacts record both the strategy state and the derived risk_policy, so experiments can verify which policy was active for each action.

Observation Context For LLM Strategy

The observation processor in aml_sim/agents/context/observation.py builds the structured context package used by the slow loop. Today that package includes:

  • agent id
  • current simulation time
  • latest market snapshot
  • cash, portfolio value, and per-instrument inventory
  • pending orders
  • recent fills
  • current strategy state
  • memory context
  • active shock/event context and known future/scheduled event context

Shock Agent

AML_Shock_Agent is the scenario-level event broadcaster for market stress, news, policy, liquidity, and other uncertainty injections. It supports:

  • Scheduled shocks with tick/time, optional notice_ticks or announce_tick, and separate announcement vs active phases.
  • Unexpected shocks through random_events templates with deterministic random_seed, per-tick probability, max event count, and severity ranges.
  • Systematic and non-systematic taxonomy through fields such as shock_class, scope, trigger_type, visibility, surprise, and expected_probability.
  • Cross-asset effects through affected_instruments, affected_asset_classes, asset_class_effects, and per_instrument_effects.
  • Central market state through initial_market_state, market_state, and market_state_delta. Temporary impacts revert after their event duration; structural changes can use state_persistence: permanent.

Supported effect fields include fundamental_price_shift, order_arrival_multiplier, risk_limit_multiplier, liquidity_multiplier, volatility_multiplier, spread_multiplier, price_impact_multiplier, rate_shift_bps, yield_shift_bps, funding_spread_bps, credit_spread_bps, sentiment_shift, and risk_aversion_shift. Current agents react mainly through price/fundamental pressure, order-arrival pressure, risk-limit pressure, liquidity withdrawal, spread/volatility widening, and sentiment shifts. The same event payload is included in the observation context so LLM slow loops can reason over active shocks and announced future events. The observation also carries the current central market state and its baseline, which the fast loops use for ongoing rate, funding, credit, liquidity, and risk conditions after an individual shock has expired.

Setup

Clone the repo with submodules in one step:

git clone --recurse-submodules <AML-Sim repo URL>
cd AML-Sim

Or clone normally, then initialize the StockSim submodule afterward:

git clone <AML-Sim repo URL>
cd AML-Sim
git submodule update --init --recursive

Create and activate a Python environment from the AML-Sim root:

python3.11 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
pip install -r requirements.txt

For the current synthetic order book scenario, no Polygon, Alpha Vantage, or OpenAI API key is required. RabbitMQ is required.

Optional root .env:

RABBITMQ_HOST=localhost
LOG_DIR=logs
OPENAI_API_KEY=sk-...

aml_runner.py will also set LOG_DIR to the run-specific log directory and will pass rabbitmq_host from the scenario to StockSim.

OpenAI is only used for scenarios or agents that explicitly configure slow_strategist.type: openai.

Start RabbitMQ

The easiest route is to use the StockSim Docker Compose file and start only RabbitMQ:

cd simulators/StockSim
docker compose up -d rabbitmq
cd ../..

Before running a scenario, make sure the RabbitMQ container is actually up:

docker ps | grep rabbitmq

This should print the running RabbitMQ container, usually named stocksim-rabbitmq. If it prints nothing, RabbitMQ is not running and StockSim agents will fail to connect to the message broker, usually with a connection refused or AMQP connection error.

Run The Current AML Scenario

From the AML-Sim root, first check that the scenario can generate a valid StockSim config:

python aml_runner.py scenarios/aml_orderbook_replay.yaml --dry-run

This creates a run directory under .aml_runs/ and writes:

.aml_runs/<run-id>/scenario.yaml
.aml_runs/<run-id>/stocksim_config.yaml
.aml_runs/<run-id>/metadata.json
.aml_runs/<run-id>/logs/
.aml_runs/<run-id>/charts/
.aml_runs/<run-id>/reports/

Completed AML runs also write trader action artifacts under:

.aml_runs/<run-id>/reports/agents/
.aml_runs/<run-id>/reports/trader_actions.json

The combined trader_actions.json report contains submitted orders, rejected orders, trade executions, strategy state at the time of the action, and portfolio/share state before and after the action.

Then run the full scenario with RabbitMQ running:

python aml_runner.py scenarios/aml_orderbook_replay.yaml

To call StockSim's post-simulation artifact generator and save reports/charts inside the AML run directory, add --reports:

python aml_runner.py scenarios/aml_orderbook_replay.yaml --reports

For the current synthetic order book scenario, this writes the StockSim summary JSON under .aml_runs/<run-id>/reports/. Future AML-specific reports should use the same run-local reports/ and charts/ folders, but can add synthetic orderbook/trade HTML views instead of relying only on external candle data.

You can set a stable run directory name while iterating:

python aml_runner.py scenarios/aml_orderbook_replay.yaml --run-id smoke_orderbook

Use a new --run-id each time, because the runner intentionally refuses to overwrite an existing .aml_runs/<run-id> directory.

Run A Small OpenAI LLM Smoke Test

scenarios/aml_llm_api_smoke.yaml enables real OpenAI slow-loop calls for only three agent groups to keep API usage small:

python aml_runner.py scenarios/aml_llm_api_smoke.yaml --dry-run
python aml_runner.py scenarios/aml_llm_api_smoke.yaml --run-id llm_api_smoke

OpenAI defaults live at the AML scenario level because the LLM call belongs to AML-Sim, not StockSim:

aml_config:
  llm:
    provider: openai
    model: gpt-5.4
    api_key_env: OPENAI_API_KEY
    temperature: 0.2
    timeout_seconds: 30
    max_retries: 2

Each configured agent can opt into those defaults like this:

slow_strategist:
  type: openai

Agent-level slow_strategist values override aml_config.llm, so one agent can use a different model or temperature for an experiment without changing the global defaults.

The OpenAI slow strategist receives profile, memory, observation, and current strategy state, then returns JSON strategy updates. It does not place orders directly; strategy updates still pass through AML validation before the fast loop can use them.

Run From The Dashboard

For local iteration, the dashboard can serve the UI and launch a simulation from one small Python server. If Docker Desktop is installed and the docker command works in your terminal, use:

python dashboard_server.py --start-rabbitmq --run --run-id one_hour_live

If Docker is not installed or is not on your PATH, start RabbitMQ manually on localhost:5672 first, then run the dashboard without --start-rabbitmq:

python dashboard_server.py --run --run-id one_hour_live

Open the printed URL, or go directly to:

http://127.0.0.1:8765/dashboard.html?run=one_hour_live

The Run Simulation button in dashboard.html works only when the page is served by dashboard_server.py, because plain python3 -m http.server 8765 cannot start local Python processes. If RabbitMQ is already running and you only want the UI/API server, use:

python dashboard_server.py

While a simulation is running, the dashboard streams run artifacts from /api/live and updates the price chart, order book, trade tape, shock monitor, participant activity, and top-line stats as the StockSim logs are written. Final report files are still loaded after shutdown for completed-run metrics.

Runs are finite by default. The scenario YAML controls the simulated clock with simulation.start_time, simulation.end_time, and simulation.tick_interval. For example, scenarios/aml_one_hour_live.yaml runs from 09:30 to 10:30 with 30-second ticks. The dashboard streams updates while this run is active; after the scenario clock reaches end_time, the run stops and the final reports are loaded. StockSim currently sleeps for roughly 5 wall-clock seconds per tick, so this one simulated hour usually takes about 10 wall-clock minutes plus startup/reporting overhead. Longer live scenarios should set simulation.max_wall_time_seconds high enough for the wall-clock runtime; the one-hour dashboard scenario uses 900 seconds.

Working With The StockSim Submodule

When editing files under simulators/StockSim, commit and push those changes from inside the submodule:

cd simulators/StockSim
git status
git add .
git commit -m "Update AML StockSim agents"
git push

Then commit the updated submodule pointer from the parent repo:

cd ../..
git status
git add simulators/StockSim
git commit -m "Update StockSim submodule"
git push

Push the StockSim commit first. The parent repo only stores a pointer to a specific StockSim commit, so other users need that commit to exist on the StockSim remote.

About

Market Simulator on top of Stocksim to study market decision making, robustness, and behavioural finance

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages